線形SVMモデル (決定境界)

線形SVM(サポートベクターマシン)は、ロジスティック回帰と同じように線形分離できるケースで高いパフォーマンスを発揮するアルゴリズムです。

線形SVMモデル構築・可視化

線形SVMモデルの構築にはscikit-learnLinearSVCクラスを使用します。(2行目)

[Google Colaboratory]

1
2
3
4
5
from sklearn.svm import LinearSVC
linear_svm = LinearSVC(random_state=0).fit(X_train_scaled, y_train)

plot_decision_regions(np.array(X_train_scaled), np.array(y_train), clf=linear_svm)
plt.show()

データセットは、これまでと同じ「乳がんの診断データ」を使用し、前回記事同様plot_decision_regionsメソッドを使い決定境界を可視化します。

[実行結果]

ロジスティック回帰とよく似た結果となりました。

ロジスティック回帰と線形SVMの違いはデータの外れ値の影響を受けにくい点です。

ロジスティック回帰は確率論に基づいたアルゴリズムでしたが、線形SVMはマージンの最大化に着目したアルゴリズムとなります。

決定境界に最も近いデータ点のことをサポートベクターと呼びますが、線形SVMはそのサポートベクターとの距離(マージン)が最大になる決定境界を引くアルゴリズムです。


なお、SVMは非線形の分類を行うこともできます。

次回は、非線形SVMでの分類を行ってみます。

ロジスティック回帰モデル② (決定境界を可視化)

データの分類予測の基準となる境界線のことを決定境界と言います。

前回構築したロジスティック回帰モデルではどのような決定境界が引かれているのかを可視化してみます。

決定境界を可視化

決定境界の可視化にはmlxtendというライブラリを使用します。

データとモデルを渡すだけで決定境界を可視化してくれるとても便利なライブラリです。

[Google Colaboratory]

1
2
3
4
5
import numpy as np
from mlxtend.plotting import plot_decision_regions

plot_decision_regions(np.array(X_train_scaled), np.array(y_train), clf=log_reg)
plt.show()

plot_decision_regionsメソッドの引数は下記の通りです。(4行目)

  • 第1引数
    スケーリングした訓練データの説明変数
  • 第2引数
    訓練データの目的変数
  • 第3引数(clf)
    構築したロジスティック回帰モデル

[実行結果]

構築したロジスティック回帰モデルでは、上図のような直線で決定境界が引かれています。

直線という制約があるので、決定境界周辺では正しく分類でいていないデータが多いようです。

ロジスティック回帰はデータを直線で分類(線形分離)できるケースに適したアルゴリズムです。

また、単純かつ計算コストが低いという特徴もあります。

ロジスティック回帰モデル① (構築)

ロジスティック回帰は、二値分類でよく使われる手法で、回帰分析のプロセスを経て分類予測を行います。

ロジスティック回帰では、重み付けされた説明変数の和から、一方に分類される確率を算出し閾値(50%)を上回るかどうかで最終的な分類を決定します。

良性に分類される確率が40%であれば悪性に分類されることになります。

ロジスティック回帰モデルの構築

ロジスティック回帰モデルを構築するには、scikit-learnLogisticRegressionクラスを使用します。

[Google Colaboratory]

1
2
3
from sklearn.linear_model import LogisticRegression

log_reg = LogisticRegression(random_state=0).fit(X_train_scaled, y_train)

予測結果を出力します。

[Google Colaboratory]

1
2
3
4
5
y_train_pred = log_reg.predict(X_train_scaled)
y_test_pred = log_reg.predict(X_test_scaled)

print(y_train_pred[:5])
print(y_test_pred[:5])

[実行結果]

ラベルデータである0, 1がきちんと出力されていることが分かります。

可視化(訓練データ)

訓練データの予測結果を可視化します。

[Google Colaboratory]

1
2
3
4
5
plt.scatter(X_train["mean radius"],X_train["mean texture"], c=y_train_pred)
plt.title("Pred_Train")
plt.xlabel("mean radius")
plt.ylabel("mean texture")
plt.show()

[実行結果]

可視化(テストデータ)

テストデータの予測結果を可視化します。

[Google Colaboratory]

1
2
3
4
5
plt.scatter(X_test["mean radius"],X_test["mean texture"], c=y_test_pred)
plt.title("Pred_Test")
plt.xlabel("mean radius")
plt.ylabel("mean texture")
plt.show()

[実行結果]

ある直線を境にきれいにデータが2分割されています。

次回は、この直線に焦点を当てて可視化を行います。

分類② (データ前処理)

モデル構築の下準備として、データの前処理を行います。

目的変数と説明変数に分割

まずデータを説明変数 X と目的変数 y に分けます。

[Google Colaboratory]

1
2
3
4
5
X= tg_df[["mean radius","mean texture"]]
y = tg_df["y"]

display(X.head())
display(y.head())

[実行結果]

訓練データとテストデータに分割

次に、データを訓練データ(70%)とテストデータ(30%)に分割します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y,test_size=0.3,random_state=0)

print(len(X_train))
display(X_train.head())
print(len(X_test))
display(X_test.head())

[実行結果]

スケーリング

最後に、データの尺度をそろえるためスケーリングを行います。

[Google Colaboratory]

1
2
3
4
5
6
7
8
from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)

print(X_train_scaled[:3])
print(X_test_scaled[:3])

[実行結果]

次回は、ロジスティック回帰モデルの構築を行います。

分類① (データ準備)

今回から、教師あり学習の1つである分類を実行していきます。

分類はデータがどのカテゴリに分類されているかを予測します。

データの読み込み

分類の問題を解くのに適した乳がん診断データを読み込みます。

悪性か良性かを目的変数として、それに寄与する検査データが説明変数として用意されているデータになります。

[Google Colaboratory]

1
2
3
from sklearn.datasets import load_breast_cancer

load_data = load_breast_cancer()

読み込んだデータをデータフレームに格納します。

またデータ件数やカラム数を出力します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
import pandas as pd

df = pd.DataFrame(load_data.data, columns = load_data.feature_names)
df["y"] = load_data.target

print(len(df))
print(len(df.columns))
display(df.head())

[実行結果]

データセットには31列569行のデータがあることが確認できました。

代表値

今回は説明変数としてmean radiusmean textureの2つのみを使用します。

describeメソッドを使って、データの代表値を確認します。

[Google Colaboratory]

1
2
tg_df = df[["mean radius","mean texture","y"]]
display(tg_df.describe())

[実行結果]

describeメソッドでは欠損値を除外して代表値を算出します。

各変数のcountとデータフレームの行数(569行)が一致しているので、このデータセットに欠損値はないことになります。

相関係数

使用する変数の相関を確認します。

[Google Colaboratory]

1
tg_df.corr()

[実行結果]

目的変数と相関も程よく強く、説明変数同士の相関が強すぎることもないので説明変数として問題ないようです。

カテゴリ数

何種類のカテゴリがあるかを確認します。

[Google Colaboratory]

1
print(tg_df["y"].unique())

[実行結果]

目的変数のユニークな値より、2種類のカテゴリがあることが確認できました。

0が悪性、1が良性のデータとなります。

カテゴリ比率

各カテゴリの比率を確認します。

[Google Colaboratory]

1
2
print(len(df.loc[tg_df["y"]==0]))
print(len(df.loc[tg_df["y"]==1]))

[実行結果]

カテゴリ比率に大きな隔たりはないようです。

カテゴリの比率に大きな隔たりがあるデータは不均衡なデータと呼ばれ、モデルの評価や学習に影響がでるので注意が必要です。

データの可視化

最後に、データをプロットしてカテゴリごとの散布状態を確認します。

[Google Colaboratory]

1
2
3
4
5
6
7
import matplotlib.pyplot as plt
%matplotlib inline

plt.scatter(tg_df["mean radius"],tg_df["mean texture"], c=tg_df["y"])
plt.xlabel("mean radius")
plt.ylabel("mean texture")
plt.show()

[実行結果]

次回からは、この2カテゴリに分類されたデータから機械学習を使って分類の傾向を調べます。

決定木アルゴリズムまとめ

これまで取り扱ってきた決定木アルゴリズムをまとめます。

決定木

木構造(樹形図)を用いて予測を行う手法です。

  • 単純な樹形図のため、モデルの解釈がしやすい。
  • 木の深さや最小サンプル数の調整で、ある程度は緩和できるものの過学習に陥るリスクが高い。

ランダムフォレスト

アンサンブル手法を用いた手法です。決定木を複数生成し学習を行います。

各決定木を並列に扱い、それぞれの結果の平均値をとります。

  • それぞれの決定木の結果の平均をとることで、予測精度は保ちつつ、過剰適合を抑制できる。
  • 決定木を複数使用するため、通常の決定木よりも計算コストが高く、またモデルが複雑になり解釈が難しくなる。

勾配ブースティング決定木(XgBoost)

アンサンブル法を用いた手法です。決定木を複数生成し学習を行います。

1つ前の決定木の誤りを修正して、次の決定木を生成します。。

  • 高い精度が出やすく、人気のある手法。
  • パラメータ設定の影響を受けやすいため、パラメータ調整には注意が必要。

パラメータチューニング手法に関してもまとめます。

グリッドサーチ

あらかじめ指定したパラメータの候補値の全通りの組み合わせを検証し、最も精度が高いパラメータの組み合わせを調べる手法です。

  • 指定したパラメータの範囲では、最もスコアが高い組み合わせを確実に得ることができる。
  • パラメータの全組み合わせ × 交差検証の分割数だけ学習・評価が行われるので、計算コストが高い。

ランダムサーチ

あらかじめ指定したパラメータの候補値のランダムな組み合わせ指定した回数だけ検証し、その中でも最も精度が高いパラメータの組み合わせを調べる手法です。

  • グリッドサーチよりも計算量が少なくて済む。
  • 最適な組み合わせが確実に得られるわけではない。

ベイズ最適化

グリッドサーチとランダムサーチの間をとったベイズ最適化という手法もあります。

ベイズ最適化はscikit-learnBayesSearchCVというクラスを使って実行できます。

勾配ブースティング③ (ランダムサーチ)

ランダムサーチ

ランダムサーチは決められた候補値のランダムな組み合わせを決められた回数だけ検証し、その限られた回数の中で最も良い評価を得たパラメータの組み合わせを導き出す手法です。

グリッドサーチの欠点である計算コストの高さを検証回数を制限することで解消した一方、パラメータ全ての組み合わせを検証するわけではないので、必ずしも最適な組み合わせを見つけることができない点が特徴になります。

ランダムサーチ用のモデル構築

ランダムサーチを行うには、scikit-learnのRandomizedSearchCVクラスを使用します。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
xgb_reg_random = xgb.XGBRegressor()
from sklearn.model_selection import RandomizedSearchCV

params = {"booster": ["gbtree"],
"n_estimators":[10,30,50,100],
"max_depth":[2, 3, 4, 5, 6],
"learning_rate":[0.1,0.25,0.5,0.75,1.0],
"colsample_bytree":[0.1,0.25, 0,5, 0.75, 1.0],
"random_state":[0]}

k_fold = KFold(n_splits=5, shuffle=True, random_state=0)
random = RandomizedSearchCV(estimator=xgb_reg_random,param_distributions=params,scoring="r2",cv=k_fold,n_iter=30,random_state=0)

random.fit(X_train,y_train)

n_iterにはランダムサーチの検証回数を指定します。(12行目)

[実行結果(一部)]

グリッドサーチよりもかなり速く処理を完了させることができました。

ランダムサーチの結果

ランダムサーチで最も評価が高かった組み合わせとそのスコアを出力します。

[Google Colaboratory]

1
2
print(random.best_params_)
print(random.best_score_)

[実行結果]

グリッドサーチではスコアが0.89でしたが、ランダムサーチではスコアが0.88と少し精度が落ちてしまっています。

今回のランダムサーチは最適なパターンまでたどり着かなかったということになります。

テストデータでの評価

最後に、テストデータを使った評価を行います。

[Google Colaboratory]

1
2
3
4
5
y_test_pred = random.predict(X_test)
y_test_pred = np.expand_dims(y_test_pred, 1)

print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

R2スコアが0.82以上となっており、グリッドサーチの0.80より良い結果となります。

最終評価にはパラメータチューニングに関与していないテストデータを使用しているので、グリッドサーチよりランダムサーチの方が良い結果となることは十分にありえます。

この点を踏まえて、どの方法でパラメータチューニングを行うかはケースによって使い分ける必要があります。

勾配ブースティング② (グリッドサーチ)

グリッドサーチ

XgBoostには、10種類を超えるハイパーパラメータがあります。

最適なパラメータの探索を効率的に行う手法として、グリッドサーチがあります。

グリッドサーチとは、あらかじめパラメータの候補値を定義しておき、それら候補値の組み合わせを全通り検証し、最も良い評価結果を出した組み合わせがどれだったのかを調べる手法です。

グリッドサーチ用のモデル構築

グリッドサーチを行うには、scikit-learnのGridSearchCVクラスを使用します。

GridSearchCVクラスは、ハイパーパラメータのそれぞれの組み合わせを交差検証法で評価し、最も評価の高かった組み合わせでモデルを学習してくれるクラスです。

[Google Colaboratory]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
xgb_reg_grid = xgb.XGBRegressor()
from sklearn.model_selection import GridSearchCV

params = {"booster": ["gbtree"],
"n_estimators":[10,30,50,100],
"max_depth":[2, 3, 4, 5, 6],
"learning_rate":[0.1,0.25,0.5,0.75,1.0],
"colsample_bytree":[0.1,0.25, 0,5, 0.75, 1.0],
"random_state":[0]}

k_fold = KFold(n_splits=5, shuffle=True, random_state=0)
grid = GridSearchCV(estimator=xgb_reg_grid,param_grid=params,cv=k_fold,scoring="r2")

grid.fit(X_train,y_train)

指定したXgBoostのパラメータの意味は以下の通りです。(4~9行目)

  • booster
    決定木系モデルか線形モデルのどちらかを指定する。
  • n_estimators
    生成する決定木の数。
    ランダムフォレストでは決定木の数を増やして平均をとるので精度面に影響はなかったが、XgBoostの場合は決定木の数を増やすほどモデルが複雑になり過学習のリスクが高まるので注意。
  • max_depth
    決定木の層の最大の深さ。
  • learning_rate
    学習率。
    以前の決定木の誤りをどれだけ強く補正するかを指定する。
    補正を強くしすぎるとモデルが複雑になり、過学習のリスクが高まる。
  • colsample_bytree
    各決定木で使用する説明変数の割合。
    1未満に指定すると、その割合だけランダムに選択された説明変数を使用する。

指定したGridSearchCVのパラメータの意味は以下の通りです。(12行目)

  • estimator
    検証で使用するモデル。
  • param_grid
    パラメータ名と値の一覧。
  • cv
    交差検証でのデータセットの分割方法
  • scoring
    評価手法。

定義したgridにデータをfitすることで、グリッドサーチが開始されます。(13行目)

[実行結果(一部)]

ハイパーパラメータの全組み合わせ × 交差検証の分割数だけ学習・評価が行われるため、計算に時間がかかります。

グリッドサーチの結果

どの組み合わせが最適だったのか、結果を確認します。

最も評価が高かった組み合わせとそのスコアを出力します。

[Google Colaboratory]

1
2
print(grid.best_params_)
print(grid.best_score_)

[実行結果]

交差検証でのスコアが0.89ととても良い評価となりました。

テストデータでの評価

最後に、テストデータを使った評価を行います。

[Google Colaboratory]

1
2
3
4
5
y_test_pred = grid.predict(X_test)
y_test_pred = np.expand_dims(y_test_pred, 1)

print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

R2スコアが0.8以上となっており、こちらもかなりよい結果です。

今回は実質4種類のパラメータの最適な組み合わせを調べましたが、XgBoostにはこの他にも多くのハイパーパラメータがあります。

それぞれのパラメータの意味を確認し、グリッドサーチを試してみることでよりよい結果にすることができるかもしれません。

勾配ブースティング① (モデルの構築・評価)

勾配ブースティング決定木は、ランダムフォレストと同じように、アンサンブル法を採用しているアルゴリズムです。

ランダムフォレストが複数の決定木を並列に扱い平均を求める手法だったのに対して、勾配ブースティングでは逐次的に決定木を生成します。

具体的に説明すると、1つ前の決定木の誤りを修正して次の決定木を生成するということを繰り返していきます。

高い精度を誇る一方、ハイパーパラメータ設定の影響を受けやすいため、パラメータの調整には注意が必要です。

勾配ブースティング決定木の代表的なものは次の2つです。

  • XgBoost
  • LightGBM

モデルの構築・評価

勾配ブースティング決定木のモデルを構築し、評価を行います。

評価方法として、k分割交差検証法を使用します。

[Google Colaboratory]

1
2
3
4
5
import xgboost as xgb

xgb_reg = xgb.XGBRegressor(random_state=0)
k_fold = KFold(n_splits=5, shuffle=True, random_state=0)
xgb_scores = cross_val_score(xgb_reg, X, y, cv=k_fold, scoring="r2")

[実行結果]

精度評価スコア

精度評価スコアを表示します。

[Google Colaboratory]

1
2
print(f"各分割のスコア:{xgb_scores}")
print(f"平均スコア:{np.mean(xgb_scores)}")

[実行結果]

平均スコアが0.83ととても良い精度となりました。

次回はより高い精度を目指して、ハイパーパラメータの調整を行います。

ランダムフォレスト② (決定木の数を変更)

ハイパーパラメータで生成する決定木の数を変更してみます。

決定木の数を変更

n_estimatorsの値を10→3に変更し、ランダムフォレストのモデルを構築します。

[Google Colaboratory]

1
rf_change_param = RandomForestRegressor(n_estimators=3, max_depth=20, random_state=0).fit(X_train,y_train)

[実行結果]

残差プロット (n_estimators=3)

予測値を算出し、残差プロットを表示します。

[Google Colaboratory]

1
2
3
4
5
6
7
y_train_pred = rf_change_param.predict(X_train)
y_test_pred = rf_change_param.predict(X_test)

y_train_pred = np.expand_dims(y_train_pred, 1)
y_test_pred = np.expand_dims(y_test_pred, 1)

residual_plot(y_train_pred, y_train, y_test_pred, y_test)

[実行結果]

決定木の数が10本のときとあまり変化は見られません。

精度評価スコア (n_estimators=3)

精度評価スコアを表示します。

[Google Colaboratory]

1
2
3
4
print("訓練データスコア")
get_eval_score(y_train,y_train_pred)
print("テストデータスコア")
get_eval_score(y_test,y_test_pred)

[実行結果]

決定木の数が10本(前回記事)のときとほぼ変わらない結果となっています。

基本的に決定木の数を増やしていくほど精度は上がっていきますが、その精度向上は徐々に収束していきます。

また、ランダムフォレストモデルでは対象データが膨大になったり、決定木の数や深さを増やすほど、処理時間が延びCPU負荷も増えますので注意が必要です。


Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×