(備忘録-python)LightGBMをOptunaで調整する方法(分類)

IT系知識

よくoptunaをつかってLightGBMの調整をするのですが、コードをなくすことが多いため備忘録も兼ねて投稿します。コピペ用に作ったので、ぜひ試してみてください。

コードのみ

ライブラリのインポート

使うライブラリのインポートを行う。

import matplotlib.pyplot as plt
%matplotlib inline
import japanize_matplotlib
import pandas as pd

import seaborn as sns
import numpy as np

from sklearn.metrics import (
    confusion_matrix,
    accuracy_score,
    precision_score,
    recall_score,
    f1_score
)

import lightgbm as lgb
import optuna

from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import fbeta_score
from sklearn.model_selection import train_test_split

混合行列の可視化と特徴量重要度の可視化

def heat_map(cm):
    cm_matrix = pd.DataFrame(data=cm,columns=['Actual Positive:1','Actual Negative:0'],
                            index=['Predict Positive:1','Predict Negative:0'])
    
    # ヒートマップで描画
    plt.figure(figsize=(3, 3))
    heatmap = sns.heatmap(cm_matrix, annot=True, fmt='d',cmap='coolwarm')
    # heatmap.set_title('混同行列',fontsize=20)
    heatmap.set_xticks([0.5,1.5])
    heatmap.set_xlabel('予測',fontsize=15)
    heatmap.set_xticklabels(['Negative:0','Positive:1'],fontsize=12)
    heatmap.set_ylabel('真値',fontsize=15)
    heatmap.set_yticks([0.5,1.5])
    heatmap.set_yticklabels(['Negative:0','Positive:1'],fontsize=12)

データのロード

以下のようにデータを準備する。

TRAIN_df=学習データ
VALID_df=検証データ

x_train=TRAIN_df[利用するカラム]
x_valid=VALID_df[利用するカラム]

target_columns=目的変数のカラム
y_train=TRAIN_df[target_columns]
y_valid=VALID_df[target_columns]

# train_test_split
X_tr, X_te, y_tr, y_te = train_test_split(x_train,y_train,random_state=42,stratify = y_train)

optunaの準備

def objective(trial):

    lgb_train = lgb.Dataset(X_tr, y_tr)
    lgb_test = lgb.Dataset(X_te, y_te, reference=lgb_train)
    
    param = {
        'task': 'train',
        'boosting_type': 'gbdt',
        'objective': 'binary',
        'metric': {'binary_error'},#binary_error

        'lambda_l1'         : trial.suggest_float('lambda_l1', 1e-8, 10.0, log=True),
        'lambda_l2'         : trial.suggest_float('lambda_l2', 1e-8, 10.0, log=True),
        'learning_rate': trial.suggest_float('learning_rate', 0.1, 1.0),
        'num_leaves': trial.suggest_int('num_leaves', 2, 256),
        'feature_fraction': trial.suggest_float('feature_fraction', 0.4, 1.0),
        'bagging_fraction': trial.suggest_float('bagging_fraction', 0.4, 1.0),
        'bagging_freq': trial.suggest_int('bagging_freq', 1, 7),
        'min_child_samples': trial.suggest_int('min_child_samples', 5, 100),

        'force_col_wise':True,
        'random_state': 0,
        }
    
    
    model = lgb.train(
                    params=param,                    # ハイパーパラメータをセット
                    train_set=lgb_train,              # 訓練データを訓練用にセット
                    valid_sets=[lgb_train, lgb_test], # 訓練データとテストデータをセット
                    valid_names=['Train', 'Test'],    # データセットの名前をそれぞれ設定
                    num_boost_round=100,              # 計算回数
                    callbacks=[lgb.early_stopping(stopping_rounds=50, verbose=1),
                               lgb.log_evaluation(10),],         # アーリーストッピング設定

                    # evals_result=lgb_results,
                    # verbose_eval=-1,                  # ログを最後の1つだけ表示
                    )
    
    # 推論
    pred = model.predict(X_te, num_iteration=model.best_iteration)
    y_pred = np.where(pred < 0.5, 0, 1) # 0.5より小さい場合0 ,そうでない場合1を返す

    # 評価
    #===========利用したい評価指標に変更===============
    score = fbeta_score(y_te, y_pred, average='binary', beta=0.5)

    return score

optunaの実行

study = optuna.create_study(direction='maximize',sampler=optuna.samplers.TPESampler(seed=42))
study.optimize(objective, n_trials=200)

print("=======ベストパラメータ========")
print(study.best_params)

調整したパラメータで学習

lgb_train = lgb.Dataset(X_tr, y_tr)
lgb_test = lgb.Dataset(X_te, y_te, reference=lgb_train)

param = {
    'task': 'train',
    'boosting_type': 'gbdt',
    'objective': 'binary',
    'metric': {'binary_error'},#binary_error
    'force_col_wise':True,
    'random_state': 0,
    }
param.update(study.best_params)


model = lgb.train(
                # **study.best_params,              # ハイパーパラメータをセット
                params=param,
                

                train_set=lgb_train,              # 訓練データを訓練用にセット
                valid_sets=[lgb_train, lgb_test], # 訓練データとテストデータをセット
                valid_names=['Train', 'Test'],    # データセットの名前をそれぞれ設定
                num_boost_round=100,              # 計算回数
                callbacks=[lgb.early_stopping(stopping_rounds=50, verbose=1),
                           lgb.log_evaluation(10),],         # アーリーストッピング設定

                # evals_result=lgb_results,
                # verbose_eval=-1,                  # ログを最後の1つだけ表示
                )


# prediction
pred = model.predict(X_te, num_iteration=model.best_iteration)
y_pred = np.where(pred < 0.5, 0, 1) # 0.5より小さい場合0 ,そうでない場合1を返す

評価

検証用データを用いて予測結果を出し、評価をする。混合行列と重要度も算出する。

pred_val = model.predict(x_valid, num_iteration=model.best_iteration)
y_pred_val = np.where(pred_val < 0.5, 0, 1) # 0.5より小さい場合0 ,そうでない場合1を返す


valid_precision=precision_score(y_valid,y_pred_val)
valid_recall=recall_score(y_valid,y_pred_val)
valid_f1=f1_score(y_valid,y_pred_val)

print(valid_precision,valid_recall,valid_f1)

混合行列の可視化。

# cm = confusion_matrix(y_valid,y_pred_val)
cm = confusion_matrix(y_pred=y_pred_val,y_true=y_valid)
heat_map(cm)
plt.xticks(rotation=90)
plt.show()

特徴量重要度の可視化。

plt.rcParams["font.size"] = 8
lgb.plot_importance(model, height = 0.5, figsize = (4,8),)

まとめ

完全に自分用の備忘録的にまとめたので詳細な説明は省いていますが、必要になったらぜひ使ってみてください。

コメント

  1. 四作 より:

    force_col_wiseはtrueにするのどういう影響があるんでしょうか?

    • ItaItsu より:

      四作さん
      コメントありがとうございます。
      当ブログは複数人体制で運営しており、コメントいただいた記事の担当者は只今不在となっています。
      しばらくお待ちいただけますと幸いです。

タイトルとURLをコピーしました