lightGBMの使い方とハイパーパラメータについて

lightGBMについて(ざっくり)

  • 回帰・クラス分類手法の一つ(XGBoostと並んでKaggleでもよく使われる人気の手法)
  • 決定木ベースの勾配ブースティング手法(Gradient Boosting Dicision Tree)
  • アンサンブル学習(複数のモデルの多数決で出力を決める手法)が使われている。
  • XGBoostとLightGBMは、大枠はほとんど同じフレームワークと考えてOK
  • LightGBMは計算量をヒストグラムとして扱うため高速に計算を実行できる。(これはXGBoostのパラメータ tree_method=histとした場合と同様)

技術的な内容の詳細は「LightGBM 徹底入門」が分かりやすい。

勾配ブースティングとは

  • ブースティング :今までに学習したモデルの情報を使って、新たのモデルを構築することでデータの学習を進める方法
    (クラス分類で誤分類されたサンプルや、回帰モデルで誤差の大きかったサンプルを改善するように新たなモデルが構築される)
  • 勾配:ブースティングにおいて、前回の学習したモデルの目的関数(損失関数)の勾配(Gradient)を用いて新たなモデルを構築する。

lightGBM のハイパーパラメータについて

Training APIとscikit-learn API のどちらを使用するかでパラメータの名前が異なる。

パラメータとモデルの性質についてのまとめ

よく調整するもの

パラメータ名
(Training API)
パラメータ名
(Scikit-learn API)
説明因数
lambda_l1reg_alphaL1正則化項の係数   0~ (float|log)
デフォルト:0
lambda_l2reg_lambdaL2正則化項の係数0~ (float|log)
デフォルト:0
num_leavesnum_leaves1本の木の最大葉枚数0~131072(int)
デフォルト:31
feature_fractioncolsample _bytree各決定木においてランダムに抽出される列の割合0~1(float)
デフォルト:1.0
bagging_fractionsubsample各決定木においてランダムに抽出される標本の割合0~1(int)
デフォルト:1.0
bagging_freqsubsample_freqここで指定したイテレーション毎にバギング実施0~(int)
デフォルト:0
min_data_in_leafmin_child_samples1枚の葉に含まれる最小データ数0~ (int)
デフォルト:20
各パラメータの大小と過剰適合の関係
小 <<<<<パラメータ名<<<<< 大
過剰適合lambda_l1
(reg_alpha)
保守的
過剰適合lambda_l2
(reg_lambda)
保守的
保守的num_leaves過剰適合
保守的feature_fraction
(colsample _bytree)
過剰適合
保守的bagging_fraction
(subsample)
過剰適合
保守的bagging_freq
(subsample_freq)
過剰適合
過剰適合min_data_in_leaf
(min_child_samples)
保守的

その他のパラメータ

パラメータ名説明引数
verbosity学習途中の情報を表示するかどうか>1:Debug
1:Info
0:Error(Warning)
-1:Fatal
デフォルト:1
n_estimatorsブースティングのラウンド数0~ (int) デフォルト:100
random_state乱数シードの値int
n_jobsLightGBM に使用するスレッド数0:デフォルトの数
-1:最大数で指定(おそらく)
デフォルト:0

コード

準備

lightGBMのインストール

conda install -c conda-forge lightgbm

データの準備など

import numpy as np
import pandas as pd

from sklearn.model_selection import cross_val_score
from sklearn.datasets import load_boston
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error

import lightgbm as lgb

boston = load_boston()

df_X = pd.DataFrame(boston.data, columns=boston.feature_names)
df_y = pd.DataFrame(boston.target,columns=['Price'])

X_train, X_test, y_train, y_test = train_test_split(df_X, df_y,test_size=0.3)

通常の方法

# データセットを生成する
lgb_train = lgb.Dataset(X_train, y_train)

# LightGBMのハイパーパラメータ
params = {'objective': 'regression'}

# 上記のパラメータでモデルを学習する
model = lgb.train(params, lgb_train)
y_pred = model.predict(X_test)

# RMSE を計算する
rmse = np.sqrt(mean_squared_error(y_test, y_pred))
print('RMSE:',round(rmse,3))
"""output
RMSE: 3.59
"""

#各変数の重要度を出す場合
"""
model.feature_importance()
#pandas DataFrameに出力
df_importance = pd.DataFrame(model.feature_importance(), 
                            index=df_X.columns,
                            columns=['importance'])
"""

各手法のパラメータ

  • 回帰問題:'regression'
  • 分類問題:'binary'
  • 多クラス類問題:'multiclass'

scikit-learn APIを使用する方法

model = lgb.LGBMRegressor()

#回帰問題の場合
#model = lgb.LGBMClassifier()

model.fit(X_train, y_train)

# テストデータを予測する
y_pred = model.predict(X_test)

# RMSEを計算する
mse = np.sqrt(mean_squared_error(y_test, y_pred))
print('RMSE:',round(rmse,3))
"""output
RMSE: 3.59
"""

#各変数の重要度を出す場合
"""
model.feature_importance()
#pandas DataFrameに出力
df_importance = pd.DataFrame(model.feature_importances_,
                            index=df_X.columns,
                            columns=['importance'])
"""

最適なブーストラウンド数を自動で決める方法

ブーストラウンド数は少なすぎると過小適合、多すぎると学習データに過剰適合してしまう恐れがあるため、適切な値を設定する必要がある。
early_stopping_roudsオプションを使うと訓練データとともに精度評価用データをモデルに渡ことで、モデルの性能が頭打ちになったところで学習を打ち切ることができ、最適なブーストラウンド数を決めることができる。
(評価用データはvalid_sets オプションで渡す。またこの際に精度評価に用いる指標も指定する必要がある)

  • n_estimators:最大のブーストラウンド数(何回学習するか)
  • early_stopping_rounds:何ラウンド進めた時に予測性能向上みられなかった時に学習を打ち切る。

精度評価に用いる指標

回帰(regression)

  • 誤差平均:'mae'
  • 二乗誤差:'mse'
  • 平均平方二乗誤差:'rmse'

二値分類

  • クロスエントロピー:'binary_logloss'
  • 正答率:'binary_error'

多クラス分類

  • Logarthmic Loss:'multi_logloss'
  • 正答率:'multi_error'

通常の方法

# データセットを生成する
lgb_train = lgb.Dataset(X_train, y_train)
lgb_eval = lgb.Dataset(X_test, y_test)

params = {'objective': 'regression',
        'metric': 'rmse',
        'early_stopping_rounds':10,
        'n_estimators':10000}

# モデル作成時に精度評価用データもわたす。
model = lgb.train(params, lgb_train, valid_sets=lgb_eval)

# 予測時には先ほど決めた学習回数を用いる。
y_pred = model.predict(X_test, num_iteration=model.best_iteration)

# RMSE を計算する
mse = np.sqrt(mean_squared_error(y_test, y_pred))
print('RMSE:',round(rmse,3))
"""output
RMSE: 3.59
"""

scikit-learn API を用いる方法

model = lgb.LGBMRegressor(n_estimators=10000)

#各ラウンドでの予測精度などを格納する辞書
evals_result = {}

model.fit(X_train, y_train,
        eval_set=[(X_train, y_train),(X_test, y_test)],
        eval_metric='mse',
        early_stopping_rounds=10,
        callbacks=[lgb.callback.record_evaluation(evals_result)],
        )

print('best iteration:',model.best_iteration_)

y_pred = model.predict(X_test)

mse = np.sqrt(mean_squared_error(y_test, y_pred))
print('RMSE:',round(rmse,3))
"""output
RMSE: 3.59
"""

参考

関連書籍