optunaというライブラリは、(ベイズ最適化等を用いて)ハイパーパラメータのチューニングを効率的に行えるものです。今回は、下記前提(基本的なモデル作成フロー)の後続として、optunaでチューニングを行ってモデル改善を試みたいと思います。

前提: データ準備~モデル作成

下記記事の通りに「データ準備からモデル作成まで行った後」として、話を進めます。

本題: チューニングしてモデル再作成

上記前提でモデルを作りましたが、より精度高いものを目指して、ハイパーパラメータをoptunaでチューニングしていきます。
尚、optunaの実装方法に関する詳細は、下記記事にまとめましたので参考にしていただければと思います。

1.目的関数を定義

「何をもって良し悪しを決め、探索するか?」を定義します。
今回は(validデータの)f1値を返す形にします。(つまり、f1値が良くなるように探索させます。)

optunaを知ったばかりの方へ、引数(trial) や suggest_xxx が何か疑問に感じるかもしれませんが、一旦は「optunaを使う際の書き方」と認識いただければと思います。詳しく知りたい方は上記記事をご参照ください。

import optuna
from lightgbm import LGBMClassifier
from sklearn.metrics import (
    accuracy_score,
    precision_score,
    recall_score,
    f1_score,
    confusion_matrix,
    roc_auc_score,
)

# 目的関数を定義。今回はf1を設定。
def objective(trial):
    model = LGBMClassifier(
        max_depth=trial.suggest_int(f"max_depth", 2, 300),
        learning_rate=trial.suggest_float(f"learning_rate", 0.001, 0.1, log=True),
        n_estimators=trial.suggest_int(f"n_estimators", 2, 300),
        min_child_samples=trial.suggest_int(f"min_child_samples", 20, 200),
        importance_type=trial.suggest_categorical(f"importance_type", ["split", "gain"]),
    )
    model.fit(X_train, y_train)
    pred_valid = model.predict(X_valid)
    f1_valid: float = f1_score(y_valid, pred_valid)
    return f1_valid

2. チューニング実施

定義した目的関数を入力として、チューニング実行(study.optimize)をします。ここで作った study は「チューニング記録を保持するもの」です。

今回の目的関数はf1ということで最大化を目指すので、「direction=”maximize”」にします。
n_trials は 探索回数であり、今回は 100 にしてみたいと思います。

study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=100)

study.optimize を実行するとログに下図のような「各trialにて使ったパラメータ値と結果、そして、そこまでのtrialにおけるベスト結果」が次々に出力されていきます。

3. 得られたベストなパラメータを使って、モデルを再作成

探索してきた結果として、最も目的関数値が良かった(validデータのf1が大きかった)時のパラメータは、study.best_params で確認できます。
それを用いて、上記前提と同じようにモデルを作成し、各種指標を確認してみます。

best_params = study.best_params
best_value = study.best_value
print(f"best_params: {best_params}")
print(f"best_value: {best_value}")
print()

best_model = LGBMClassifier(**best_params)
best_model.fit(X_train, y_train)

# predict
pred_valid = best_model.predict(X_valid)
score_valid = best_model.predict_proba(X_valid)[:, 1]
print(f"pred_valid: {pred_valid.shape}, data: {pred_valid[:5]}")
print(f"score_valid: {score_valid.shape}, data: {score_valid[:5]}")
print()

# 精度チェック
print(f"accuracy_score: {accuracy_score(y_valid, pred_valid):.2%}")
print(f"precision_score: {precision_score(y_valid, pred_valid):.2%}")
print(f"recall_score: {recall_score(y_valid, pred_valid):.2%}")
print(f"f1_score: {f1_score(y_valid, pred_valid):.2%}")
print(f"roc_auc: {roc_auc_score(y_valid, score_valid):.2%}")

sns.heatmap(confusion_matrix(y_valid, pred_valid), annot=True, cmap='Blues')

結果、(上記前提の時に比べ)下記の通り、下記指標の全てが良くなりました。
このように、optunaを使う事でチューニングが簡単に実装できます。
 ・accuracy_score: 82.84% ( ← 80.97% )
 ・precision_score: 79.38% ( ← 77.08% )
 ・recall_score: 74.76% ( ← 71.84% )
 ・f1_score: 77.00% ( ← 74.37% )
 ・roc_auc: 84.93% ( ← 84.17% )

By clear

データエンジニア・機械学習・分析等を主とし、Webアプリ開発も行っているフリーランスです。