この記事ではスタッキングについてvecstackの使い方をrisを例として説明します。
スタッキングとは
スタッキングは異なる予測器を1層2層…と重ねていき予測の精度を高めるアンサンブル手法です。下の層の予測を上の層の特徴量として入力します。
1層目以降に設定された予測器が予測を出力し、その結果を上の層に入力します。下の層からの入力を受け取ったら正解データと照らし合わせてどの分類機が信用できるかを上の層が判断して結果をまた上の層に入力します。これを繰り返して一番上にある予測器が最終的な予測を出力します。
vecstack作者によるスタッキングの解説(Stacking understanding. Python package for stacking)が分かりやすそうです。
vecstackを使ったスタッキング
vecstackはスタッキングを実現するためのライブラリです。
veckstackの特徴は
- 実装が楽
- 多層のスタックが簡単に構築できる
- scikit-learn APIにも対応している
- サンプルが分かりやすい
です。
Function API
以下のサンプルではirisデータセットの分類問題を例にvecstackを使います。
1層目にKNeighborsとLightGBMのモデルをセットして最終層にはXGBoostを設定しています。
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from lightgbm import LGBMClassifier
from sklearn.neighbors import KNeighborsClassifier
from xgboost import XGBClassifier
from vecstack import stacking
iris = load_iris()
df = pd.DataFrame(data= np.c_[iris['data'], iris['target']],
columns= iris['feature_names'] + ['target'])
X = df.loc[:,["sepal width (cm)","petal width (cm)","petal length (cm)"]]
y = df.loc[:,"target"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=0.3, random_state=0)
models = [
KNeighborsClassifier(),
LGBMClassifier()
]
S_train, S_test = stacking(models,
X_train, y_train, X_test,
regression=False, # 分類問題(classifier)なのでFalse
mode='oof_pred_bag',
needs_proba=False,
save_dir=None,
metric=accuracy_score,
n_folds=4,
stratified=True,
shuffle=True,
random_state=0,
verbose=2)
model = XGBClassifier(random_state=0, n_jobs=-1, learning_rate=0.1, n_estimators=100, max_depth=3)
model = model.fit(S_train, y_train)
y_pred = model.predict(S_test)
print('accuracy: ', accuracy_score(y_test, y_pred))
これを実行すると以下のような出力が得られます。
$ python stacking.py
task: [classification]
n_classes: [3]
metric: [accuracy_score]
mode: [oof_pred_bag]
n_models: [2]
model 0: [KNeighborsClassifier]
fold 0: [0.96296296]
fold 1: [0.88461538]
fold 2: [1.00000000]
fold 3: [1.00000000]
----
MEAN: [0.96189459] + [0.04710961]
FULL: [0.96190476]
model 1: [LGBMClassifier]
fold 0: [0.96296296]
fold 1: [0.84615385]
fold 2: [0.96153846]
fold 3: [1.00000000]
----
MEAN: [0.94266382] + [0.05781418]
FULL: [0.94285714]
accuracy: 0.9777777777777777
scikit-learn API
veckstackはscikit-learn APIも提供しています。以下に実装例を示します。
StackingTransformer
はsklearnのPipelineに入れる形式に分類器を変換するものです。
また、StackingTransformer
中のvariableは、GitHubのREADMEによると’A’にすると結果を維持したまま時間が短くなるそうです。
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from lightgbm import LGBMClassifier
from sklearn.neighbors import KNeighborsClassifier
from xgboost import XGBClassifier
from sklearn.pipeline import Pipeline
from vecstack import StackingTransformer
iris = load_iris()
df = pd.DataFrame(data= np.c_[iris['data'], iris['target']],
columns= iris['feature_names'] + ['target'])
X = df.loc[:,["sepal width (cm)","petal width (cm)","petal length (cm)"]]
y = df.loc[:,"target"]
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=0.3, random_state=0)
estimators_L1 = [
('kn', KNeighborsClassifier()),
('lgbm', LGBMClassifier()),
]
stack = StackingTransformer(estimators=estimators_L1,
regression=False,
variant='A', # https://github.com/vecxoz/vecstack#24-which-stacking-variant-should-i-use-a-oof_pred_bag-or-b-oof_pred
metric=accuracy_score,
n_folds=4,
shuffle=True,
random_state=0,
verbose=2)
final_estimator = XGBClassifier(random_state=0, n_jobs=-1, learning_rate=0.1)
steps = [('stack', stack),
('final_estimator', final_estimator)]
pipe = Pipeline(steps)
pipe = pipe.fit(X_train, y_train)
y_pred_pipe = pipe.predict(X_test)
print('accuracy: ', accuracy_score(y_test, y_pred_pipe))
実行すると以下のように出力されます。
$ python stacking.py
task: [classification]
n_classes: [3]
metric: [accuracy_score]
variant: [A]
n_estimators: [2]
estimator 0: [kn: KNeighborsClassifier]
fold 0: [0.96296296]
fold 1: [1.00000000]
fold 2: [0.96153846]
fold 3: [0.92307692]
----
MEAN: [0.96189459] + [0.02720341]
(中略)
estimator 1: [lgbm: LGBMClassifier]
model from fold 0: done
model from fold 1: done
model from fold 2: done
model from fold 3: done
----
DONE
accuracy: 0.9777777777777777
scikit-learn APIは公式サンプルを参考にしました。
まとめ
vecstackを使うと多層のスタッキングを楽に構築することができることが分かりました。実際に使うときはまずvecstackのGitHubのREADMEを読むといいと思います。Stacking FAQ
の欄にスタッキングに関する1問1答が30項目載っていてスタッキングをするにあたって非常に良い資料となっています。