パラメータチューニング

〇パラメータとは?

 -モデルを作る際の設定値や制限値。
 -機械学習では自動的には学習してくれない。
 -モデルの性能を大きく左右する。

〇料理にたとえると、、、
 ・データ → 食材
 ・パラメータ → 加熱時間、分量、など
 ・アルゴリズム → レシピ


〇交差検証

 →パラメーターのチューニング方法の1つ。
 →分割によって学習・評価データのパターンを複数つくり、モデルの汎化性能を評価する方法。
 →K分割交差検証は、データをK個(3~5)に分割。

①すべてのデータがすべて1度だけ評価に用いられるため、すべてのサンプルに対していい汎化性能を示さないと、高いスコアを出せない。
②すべてのデータを効率的に利用できるため、より正確なモデルができる。


欠点
 →計算時間コスト。


〇グリッドサーチ

 -パラメータの候補から、すべての組み合わせを試す。
 -性能の評価には交差検定を利用する。
 -探索した結果から最適なパラメータの組み合わせを選ぶ


〇グリッドサーチの前準備

①関数のインポート

from sklearn.model_selection import GridSearchCV

②グリッドサーチの設定準備

 ・モデルの箱を代入した変数(必須)

 model = DT(random_state=0)

 ・探索するパラメータとその範囲を代入した変数(必須)

parameters = {パラメータの名前①:[値1,値2,値3,,,], パラメータの名前②:[値1,値2,値3,,,]}

 ・クロスバリデーションの分割数
 ・評価に使用する関数

③グリッドサーチの設定

GridSearchCV(モデルの箱, パラメータの範囲を表す変数, cv=クロスバリデーションの分割数, scoring="評価指標", return_train_score=True)


例)

# 決定木モデルのインポート
from sklearn.tree import DecisionTreeClassifier as DT

# グリッドサーチのインポート
from sklearn.model_selection import GridSearchCV

# 決定木モデルの準備
model = DT(random_state=0)

# パラメータの準備
parameters = {"max_depth":[2,3,4,5,6,7,8,9,10]}

# グリッドサーチの設定
gcv = GridSearchCV(model, parameters, cv=5, scoring='roc_auc', return_train_score=True)


〇グリッドサーチの実行

grid.fit(説明変数, 目的変数)


〇グリッドサーチの結果の確認

<確認事項>
 ・モデルの学習にかかった時間
 ・予測にかかった時間
 ・学習に用いたデータを使って評価した精度
 ・学習には用いなかったデータを使って評価した精度

※特に重要な後半2つの項目を取り出す場合。

grid.cv_results_['mean_train_score']
gric.cv_results_['mean_test_score']


# 評価スコアの取り出し
train_score = gcv.cv_results_['mean_train_score']
test_score = gcv.cv_results_['mean_test_score']
print(train_score)
print(test_score)
[0.75189177 0.82608925 0.8511899  0.86495018 0.8783299  0.89220921 

0.90611839 0.91879575 0.93225731] 

[0.75059503 0.82466539 0.84533595 0.85490475 0.86086691 0.85425 

0.84496702 0.82709776 0.80383339] 

・パラメータを2から10まで変えたときのAUCスコアがリストとして返された。
・mean_train_scoer,mean_test_scoreのmeanは分割数を5にしたので5回分の平均を表しています。



〇train_scoreとtest_scoreの比較

パラメータmax_depthを範囲2~10で変えたとき、どう変化したかを可視化したうえで比較してみる。

・X軸・・・max_depth
・y軸・・・AUCスコア

# 評価スコアの取り出し
train_score = gcv.cv_results_["mean_train_score"]
test_score = gcv.cv_results_["mean_test_score"]

# matplotlib.pyplotを省略名pltとしてインポート 
import matplotlib.pyplot as plt

# 学習に用いたデータを使って評価したスコアの描画
plt.plot([2,3,4,5,6,7,8,9,10], train_score, label="train_score")

# 学習には用いなかったデータを使って評価したスコアの描画
plt.plot([2,3,4,5,6,7,8,9,10], test_score, label="test_score")

# グラフにタイトルを追加
plt.title('train_score vs test_score')

# グラフのx軸に名前を追加
plt.xlabel('max_depth')

# グラフのy軸に名前を追加
plt.ylabel('AUC')

# 凡例の表示
plt.legend()

# グラフの表示
plt.show()

画像1

・train_scoreは、max_depthの値が大きくなるにつれて、スコアが上昇している。一方、test_scoreはmax_septh=6をピークにスコアが低下している。

・max_depthが6を超えたとき、train_scoreは向上しているのにtest_scoreが低下しているのは、モデルが学習データに適合しすぎた結果、未知データに対しては適合できていない。(汎化性能がない)状態を表す。この状態は過学習。

・train_scoreとtest_scoreのパラメータによる変化を可視化することによって、過学習になるタイミングを可視化することが出来る。


〇最適パラメータモデルによる
 予測・評価

最適なパラメータが何だったのかは、best_prams_を使って確認することが出来る。

grid.best_params_

最適なパラメータで学習された母出るは、best_estimator_を使って、利用することが出来る。

grid.best_estimator_


例)

# 最適なパラメータの表示
print( gcv.best_params_ )

# 最適なパラメータで学習したモデルの取得
best_model = gcv.best_estimator_

# 評価用データの予測(予測結果が1である確率のみ抜き出す)
pred_y3 = best_model.predict_proba(test_X)[:,1]

# AUCの計算
auc3 = roc_auc_score(test_y, pred_y3)

# AUCの表示
print ( auc3 )
{'max_depth': 6} 

0.8631100075115532 


〇ROC曲線の描画

1回目・・・max_depth=2
2回目・・・max_depth=10
3回目・・・max_depth=6

の3つの決定木モデルを作りました。
それぞれのRoc曲線を描き、比較してみましょう。

# matplotlib.pyplotのインポート
from matplotlib import pyplot as plt

# roc_curveのインポート
from sklearn.metrics import roc_curve

# 偽陽性率、真陽性率、閾値の計算
# なお、予測結果は以下の変数に代入されているものとします。
# pred_y1:max_depth=2の場合の予測結果
# pred_y2:max_depth=10の場合の予測結果
# pred_y3:max_depth=6の場合の予測結果
# また、それぞれの戻り値を代入する変数は以下とします。
# fpr1,tpr1,thresholds1:max_depth=2の場合の偽陽性率、真陽性率、閾値
# fpr2,tpr2,thresholds2:max_depth=10の場合の偽陽性率、真陽性率、閾値
# fpr3,tpr3,thresholds3:max_depth=6の場合の偽陽性率、真陽性率、閾値
fpr1, tpr1, thresholds1 = roc_curve(test_y, pred_y1)
fpr2, tpr2, thresholds2 = roc_curve(test_y, pred_y2)
fpr3, tpr3, thresholds3 = roc_curve(test_y, pred_y3)

# ラベル名の作成
# なお、それぞれの戻り値を代入する変数は以下とします。
# roc_label1:max_depth=2の場合のラベル名
# roc_label2:max_depth=10の場合のラベル名
# roc_label3:max_depth=6の場合のラベル名
roc_label1='ROC(AUC={:.2}, max_depth=2)'.format(roc_auc_score(test_y, pred_y1))
roc_label2='ROC(AUC={:.2}, max_depth=10)'.format(roc_auc_score(test_y, pred_y2))
roc_label3='ROC(AUC={:.2}, max_depth=6)'.format(roc_auc_score(test_y, pred_y3))
# ROC曲線の作成
plt.plot(fpr1, tpr1, label=roc_label1)
plt.plot(fpr2, tpr2, label=roc_label2)
plt.plot(fpr3, tpr3, label=roc_label3)

# 対角線の作成
plt.plot([0, 1], [0, 1], color='black', linestyle='dashed')

# グラフにタイトルを追加
plt.title('ROC')

# グラフのx軸に名前を追加
plt.xlabel('FPR')

# グラフのy軸に名前を追加
plt.ylabel('TPR')

# x軸の表示範囲の指定
plt.xlim(0, 1)

# y軸の表示範囲の指定
plt.ylim(0, 1)

# 凡例の表示
plt.legend()

# グラフを表示
plt.show()

画像2

・グリッドサーチで探索した最適パラメータであるmax_depth=6で学習したモデルはAUCが大きくなっている。

・過学習はしていないと考えられる。(train_socro vs test_scoreより)


〇決定木の描画

# 最適なパラメータで学習したモデルの取得
best_model = gcv.best_estimator_

# 決定木描画ライブラリのインポート
from sklearn.tree import export_graphviz

# 決定木グラフの出力
export_graphviz(best_model, out_file="tree.dot", feature_names=train_X.columns, class_names=["0","1"], filled=True, rounded=True)

# 決定木グラフの表示
from matplotlib import pyplot as plt
from PIL import Image
import pydotplus
import io
g = pydotplus.graph_from_dot_file(path="tree.dot")
gg = g.create_png()
img = io.BytesIO(gg)
img2 = Image.open(img)
plt.figure(figsize=(img2.width/100, img2.height/100), dpi=75)
plt.imshow(img2)
plt.axis("off")
plt.show()

画像3

・階層の深さが6の大きな木となったことで、階層深さ2に比べ、複雑な表現が可能になった。

・一方、階層を深くしたことで、人が理解するのが少し難しくなった。

・ターゲティングモデルのブラッシュアップ成功!







この記事が気に入ったらサポートをしてみませんか?