lightgbmをoptunaで楽にチューニングしたい
optunaは下準備にコードを書く必要がありますが、lightgbmが対象の場合は、より簡単なコードで処理することができます。
コード
lightbgmでtrainしていたところを、optuna.integration.lightgbmに変えるだけです。
▼lightgbmに関してはこちら
下準備
import lightgbm import optuna.integration.lightgbm as lgbo from sklearn.model_selection import train_test_split # 回帰の場合 opt_params = { "objective":"regression", "metric":"rmse" } # データを用意する X_train,X_test,y_train,y_test = train_test_split( boston_X, boston_y, test_size=0.2) reg_train = lgb.Dataset( X_train, y_train ) reg_eval = lgb.Dataset( X_test, y_test, reference=reg_train )
パラメータを探す
#パラメータを探す opt=lgbo.train( opt_params, reg_train, valid_sets = reg_eval, verbose_eval=False, #ラウンド数 num_boost_round = 5, #打ち切り #early_stopping_rounds = 100 )
パラメータを確認
#最適なパラメータを取得
opt.params
{'objective': 'regression',
'metric': 'rmse',
'lambda_l1': 0.06827725234472487,
'lambda_l2': 0.0026080375045565317,
'num_leaves': 31,
'feature_fraction': 1.0,
'bagging_fraction': 1.0,
'bagging_freq': 0,
'min_child_samples': 5}
あとはこれをモデルに渡し、再学習します。
ベイズ最適でハイパラチューニングをしたい(optunaを使う)
ハイパーパラメータのチューニングをする場合、グリッドサーチでは非常に時間がかかることがあります。
対して、ベイズを用いたハイパーパラメータチューニングは非常に早く実行できます。
今回はそのためにoptunaを使用します。
基本的な使い方
最大化、最小化する目的関数を作成し、それを最適化します。
目的関数の作成
探索するハイパーパラメータはtrial.xxxで型、範囲、名前を定義します。
import optuna from sklearn.metrics import accuracy_score def objective(trial): params = { "min_samples_split":trial.suggest_int("min_samples_split", 8, 16), "max_leaf_nodes":int(trial.suggest_discrete_uniform("max_leaf_nodes", 4, 64, 4)), "criterion":trial.suggest_categorical("criterion", ["gini", "entropy"]) } rfc = RandomForestClassifier(**params) rfc.fit(rfc_data['X_train'], rfc_data["y_train"]) #return #1.0 - accuracy_score(rfc_data["y_test"], rfc.predict(rfc_data["X_test"])) return accuracy_score(rfc_data["y_test"], rfc.predict(rfc_data["X_test"]))
プロセスの定義
directionで最小化か、最大化か、過程をsqliteに書き込むかなどを指定し、optimizeで実行します。
study_name = 'rfc_optimize' s = optuna.create_study( study_name = study_name, direction='maximize', storage='sqlite:///example.db', load_if_exists=True #途中までの結果があればそれを利用する ) s.optimize(objective,n_trials=10) #結果の確認 s.best_params s.best_value
その他便利な物
sqliteに入れた場合は、sqlite3で確認できます。
sqlite3 example.db .table select * from trials
また、studyからデータフレームで確認したり、可視化をすることもできます。(plotlyのextensionが必要になります)
s.trials_dataframe(attrs=('number', 'value', 'params', 'state')) #ハイパーパラメータの重要度 optuna.visualization.plot_param_importances(s) #過程の可視化 optuna.visualization.plot_optimization_history(s)
予測の解釈がしたい(SHAPを使う)
Limeでレコード単位での予測の把握をすることはできますが、それを全体化したものを見てみたい場合があります。 そうした時はSHAPを使うと便利です。
コード
セットアップ
import shap
shap.initjs()
#ランダムフォレストなどのモデルを渡す ex = shap.TreeExplainer(mdl) #トレインデータを渡す shap_v = ex.shap_values(boston_X)
可視化
個別データの可視化
まずはLimeと同様に個別のデータを見てみます
shap.force_plot(
ex.expected_value,
shap_v[15,:],
boston_train_X[15,:], #対象レコード
feature_names = boston['feature_names']
)

各レコードを同時に可視化してみます。 元の順番や、目的変数の大きさで並べることができます。
shap.force_plot(
base_value=ex.expected_value,
shap_values=shap_v,
feature_names=boston['feature_names']
)
]
特徴そのものの確認
特徴のインパクトの大きさや、特徴量内の大きさがどう影響しているのかを平面で表現できます。
#特徴量のインパクト shap.summary_plot( shap_v, boston_test_X, #予測データ plot_type="bar", feature_names = boston['feature_names'] ) shap.summary_plot( shap_v, boston_test_X, feature_names = boston['feature_names'] )

個別の変数の増減、他の変数との関係、SHAP値との関係も見ることができます。
shap.dependence_plot(
ind='ZN',
interaction_index = 'AGE',
shap_values=shap_v,
#features=pd.DataFrame(boston_X,columns =load_boston()['feature_names'])
features = boston_test_X,
feature_names = boston['feature_names']
)
ZNが40くらいまでは加工し、そこからは上昇していき、その群はAGEが40以下くらい、といったところでしょうか。