GridSearchCV(scikit-learn)によるチューニング

投稿者: | 2018-04-07

Pythonの機械学習ライブラリscikit-learnにはモデルのパラメタをチューニングする仕組みとしてGridSearchCVが用意されています。

ここではGridSearchCVの使い方を紹介し、実行例としてscikit-learnに用意されているBoston house-pricesデータセットを題材にGridSearchCVを使ってElasticNetのパラメタチューニングをしてみます。

なお、PythonのスクリプトはGitHubにあげているのでそちらをご参照ください。

GridSearchCVの使い方

GridSearchCVを使うと指定したパラメタの全組合せの中からCross validationで最も良いパラメタを求めることができます。

from sklearn.model_selection import GridSearchCV
GridSearchCV(estimator, param_grid, scoring=None, fit_params=None, n_jobs=1, iid=True, refit=True, cv=None, verbose=0, pre_dispatch=‘2*n_jobs’, error_score=’raise’, return_train_score=’warn’)

主な引数として

  • estimator: チューニングを行うモデル
  • param_grid: パラメタ候補値を「パラメタ名, 候補値リスト」の辞書で与える
  • n_jobs: 同時実行数(-1にするとコア数で同時実行)
  • refit: Trueだと最良だったパラメタを使い学習データ全体で再学習する
  • cv: Cross validationの分割数(default: 3分割)
  • verbose: ログ出力レベル

を指定できます。

例えばL1正則化とL2正則化を組合せたモデルであるElasticNetでは精度に大きな影響を与えるパラメタとして

  • alpha: 正則化の強さ。0以上の値を取り0だと線形回帰を同じになる
  • l1_ratio: L1正則化とL2正則化のウェイトで0〜1の値をとる

があります。

  • alpha = [math]10^{-3}, 10^{-2}, \cdots, 10^2, 10^3[/math]
  • l1_ratio = [math]0.1, 0.2, \cdots, 0.8, 0.9[/math]

の組合せの中から最も良いパラメタを探したい場合はX_train, y_trainをそれぞれ学習データの説明変数、目的変数として

from sklearn.linear_model import ElasticNet
from sklearn.model_selection import GridSearchCV
import numpy as np

alpha_params = np.logspace(-3, 3, 7)
l1_ratio_params = np.arange(0.1, 1.0, 0.1)

paramters = {
    'alpha': alpha_params,
    'l1_ratio': l1_ratio_params
}

# パラメタチューニング
model_tuning = GridSearchCV(
    estimator = ElasticNet(),  # 識別器
    param_grid = paramters,    # パラメタ
)

model_tuning.fit(X_train, y_train)

と実行するとalpha(7通り)とl1_ratio(9通り)の全63通りのパラメタごとに3-fold cross validationで評価し最も良いパラメタを探してくれます。最も良いパラメタ、モデルは

best_param = model_tuning.best_params_
best_estimator = model_tuning.best_estimator_

で得られます。

非常に便利な機能ですが

「パラメタの全組合せ」[math]\times[/math]「cross validationの分割数」

の回数だけモデルを構築/評価するのでパラメタ数やGrid数が多いと膨大な計算時間がかかってしまいます。そのためパラメタチューニングをする際は

  • 動かすパラメタを影響の大きなパラメタに絞る
  • パラメタを粗めに動かす

として順次、パラメタの範囲を絞り込んだり、チューニングしたパラメタを固定した上で他のパラメタを追加していくのが良いと思います。

GridSearchCVの実行例

Boston house-pricesデータセット

scikit-learnには回帰分析用のデータセットとしてボストン市の住宅価格のデータセットBoston house-pricesが用意されています。犯罪率などの13個の説明変数から住宅価格を予測する問題設定となっており506個のサンプルが格納されています。

Boston house-pricesデータを読み込んで学習/評価用データに分割しておきます。

from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split

# Boston house-pricesのロード
boston = load_boston()

X = boston.data
y = boston.target

# 学習データと評価データに分割(分割比率8:2)
(X_train, X_test, y_train, y_test) = train_test_split(X, y, test_size=0.2, random_state=0)

ElasticNetでの予測

まずベースモデルとしてデフォルトパラメタ[1]今回用いたscikit-learn v0.19.1ではalpha=1.0, l1_ratio=0.5で予測した時のR2 score(決定係数)を求めてみましょう。

from sklearn.linear_model import ElasticNet
from sklearn.metrics import r2_score

# デフォルトパラメタ
elastic_net = ElasticNet()
elastic_net.fit(X_train, y_train)

# 評価データでのR2スコアを算出
pred = elastic_net.predict(X_test)
score = r2_score(y_test, pred)

print('ElasticNet(default) R2 score: %.3f' % score)

実行するとR2 score = 0.501だとわかります。

ElasticNetのチューニング

上の例と同様にalpha = [math]10^{-3}, 10^{-2}, \cdots, 10^2, 10^3[/math], l1_ratio = [math]0.1, 0.2, \cdots, 0.8, 0.9[/math]と動かして5-fold cross validationでパラメタチューニングをしてみます。

from sklearn.model_selection import GridSearchCV
import numpy as np

# チューニングモデル
estimator = ElasticNet()

# モデルのパラメタ候補を定義
alpha_params = np.logspace(-3, 3, 7)
l1_ratio_params = np.arange(0.1, 1.0, 0.1)

paramters = {
    'alpha': alpha_params,
    'l1_ratio': l1_ratio_params
}

# パラメタチューニング
model_tuning = GridSearchCV(
    estimator = estimator,     # 識別器
    param_grid = paramters,    # パラメタ
    cv = 5,                    # Cross validationの分割数
    n_jobs = -1,               # 並列実行数(-1: コア数で並列実行)
)

model_tuning.fit(X_train, y_train)

いきなり最良モデルの精度評価をしても良いですが、パラメタの範囲が妥当だったか各パラメタでの精度をplotしてみましょう。

横軸がl1_rationの値で縦軸がR2 score値でalphaの値ごとに折れ線グラフを作っています。これを見ると

  • alpha=0.001〜0.1でscoreが高く、ほとんど差はない
  • alpha=0.001〜0.1ではl1_ratioを変えてもscoreはほとんど変わらない

なので得られたパラメタ良さそうです。(もう1回チューニングするならalpha=0.001〜0.1の範囲で細かく刻むのがよいでしょう。)

チューニングしたモデルを評価すると

# チューニングしたモデルを評価
elastic_net_tuned = model_tuning.best_estimator_

# 評価データでのR2スコアを算出
pred = elastic_net_tuned.predict(X_test)
score = r2_score(y_test, pred)

print('ElasticNet(tuned) R2 score: %.3f' % score)

実行するとR2 score = 0.588となりベースモデル(score = 0.501)から改善していることがわかります。

参考情報

脚注

1 今回用いたscikit-learn v0.19.1ではalpha=1.0, l1_ratio=0.5

スポンサーリンク


GridSearchCV(scikit-learn)によるチューニング」への1件のフィードバック

  1. ピンバック: [Kaggle]いろいろとTitanicしてみる:グリッドサーチ | IT技術情報局

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です