LightGBM

2.4.7

LightGBM

最終更新 2020-04-22 読了時間 2 分
まとめ
  • LightGBMはMicrosoftが開発した勾配ブースティングライブラリで、ヒストグラム近似と葉優先(Leaf-wise)の木構築で大規模データを高速に処理する。
  • カテゴリ変数のネイティブ処理、GPU学習、分散学習に対応し、前処理の手間を削減できる。
  • num_leaveslearning_raten_estimatorsmin_child_samplesが主なチューニング対象。

直感 #

通常の勾配ブースティングは木をレベルごとに均等に成長させるが、LightGBMは損失をもっとも減らせる葉を優先的に分割する(Leaf-wise)。これにより同じ木の数でも精度が出やすく、学習も速い。さらにヒストグラム近似で分割候補を大幅に減らすため、大規模データでも実用的な速度で動作する。

詳細な解説 #

ライブラリと実験データ #

import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
from lightgbm import LGBMClassifier
X, y = make_classification(
    n_samples=1000, n_features=20, n_informative=10,
    n_redundant=5, random_state=42
)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.3, random_state=42
)

基本的な学習と評価 #

model = LGBMClassifier(
    n_estimators=100,
    num_leaves=31,
    learning_rate=0.1,
    random_state=42,
    verbose=-1,
)
model.fit(X_train, y_train)
y_prob = model.predict_proba(X_test)[:, 1]
print(f"ROC-AUC: {roc_auc_score(y_test, y_prob):.4f}")

num_leavesの影響 #

num_leavesは木の最大葉数を制御します。大きくすると表現力が上がるが、過学習しやすくなります。max_depthよりも直接的にモデルの複雑さを決定するパラメーターです。

leaves_list = [8, 16, 31, 63, 127]
scores = []
for nl in leaves_list:
    m = LGBMClassifier(
        n_estimators=100, num_leaves=nl,
        learning_rate=0.1, random_state=42, verbose=-1,
    )
    m.fit(X_train, y_train)
    scores.append(roc_auc_score(y_test, m.predict_proba(X_test)[:, 1]))

plt.figure(figsize=(8, 4))
plt.plot(leaves_list, scores, "o-")
plt.xlabel("num_leaves")
plt.ylabel("ROC-AUC")
plt.title("num_leavesと精度の関係")
plt.grid(True)
plt.show()

learning_rateの影響 #

rates = [0.01, 0.05, 0.1, 0.3, 0.5]
scores = []
for lr in rates:
    m = LGBMClassifier(
        n_estimators=200, num_leaves=31,
        learning_rate=lr, random_state=42, verbose=-1,
    )
    m.fit(X_train, y_train)
    scores.append(roc_auc_score(y_test, m.predict_proba(X_test)[:, 1]))

plt.figure(figsize=(8, 4))
plt.plot(rates, scores, "o-")
plt.xlabel("learning_rate")
plt.ylabel("ROC-AUC")
plt.title("learning_rateと精度の関係")
plt.grid(True)
plt.show()

min_child_samplesの影響 #

葉ノードの最小サンプル数を増やすと、過学習を抑制できます。

min_samples = [5, 10, 20, 50, 100]
scores = []
for ms in min_samples:
    m = LGBMClassifier(
        n_estimators=100, num_leaves=31,
        learning_rate=0.1, min_child_samples=ms,
        random_state=42, verbose=-1,
    )
    m.fit(X_train, y_train)
    scores.append(roc_auc_score(y_test, m.predict_proba(X_test)[:, 1]))

plt.figure(figsize=(8, 4))
plt.plot(min_samples, scores, "o-")
plt.xlabel("min_child_samples")
plt.ylabel("ROC-AUC")
plt.title("min_child_samplesと精度の関係")
plt.grid(True)
plt.show()

特徴量の重要度 #

importances = model.feature_importances_
indices = np.argsort(importances)[::-1]

plt.figure(figsize=(10, 5))
plt.bar(range(len(importances)), importances[indices])
plt.xlabel("特徴量インデックス")
plt.ylabel("重要度(split)")
plt.title("LightGBM 特徴量重要度")
plt.show()

Level-wiseとLeaf-wiseの違い #

通常の勾配ブースティング(XGBoostのデフォルトなど)はLevel-wise、すなわち深さごとに全ノードを分割します。一方LightGBMはLeaf-wise、つまり損失をもっとも減らせる葉だけを分割します。

  • Level-wise: バランスの取れた木になりやすく、過学習しにくい
  • Leaf-wise: 同じ葉数ならより低い損失を達成できるが、深くなりすぎると過学習する

このため、LightGBMではmax_depthよりもnum_leavesでモデルの複雑さを制御するのが基本です。