複数の機械学習モデルを組み合わせる方法の一つとしてスタッキングがありますが、Python の scikit-learnのStackingClassifierとStackingRegressorを使ってみました。
StackingClassifier
スタッキングによる分類
分類モデルの性能を確認するため、乳がんデータを使ってみます。
from sklearn.datasets import load_breast_cancer
X, y = load_breast_cancer(return_X_y=True)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y)
ろくなパラメータチューニングもしてないので改良の余地はありますが、とりあえず
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVC
from sklearn.ensemble import StackingClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.linear_model import LogisticRegression
estimators = [
('svc', make_pipeline(StandardScaler(), SVC())),
('rf', RandomForestClassifier()),
('mlp', MLPClassifier(max_iter=10000))
]
clf = StackingClassifier(
estimators=estimators,
final_estimator=LogisticRegression(max_iter=10000)
)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
0.972027972027972
単独の分類モデルの性能
比較として、単独の分類モデルの正解率を計算してみます。
make_pipeline(StandardScaler(), SVC()).fit(X_train, y_train).score(X_test, y_test)
0.965034965034965
RandomForestClassifier().fit(X_train, y_train).score(X_test, y_test)
0.951048951048951
MLPClassifier(max_iter=10000).fit(X_train, y_train).score(X_test, y_test)
0.9090909090909091
LogisticRegression(max_iter=10000).fit(X_train, y_train).score(X_test, y_test)
0.958041958041958
単独で使うよりも、組み合わせた方が良いという結果になりました。
ですが、train_test_split から計算し直すと、分割のされ方によっては単独の分類モデルのほうが性能が良くなったりします。
性能比較には、ランダムシードを固定せずに、何度も計算を繰り返して、その性能がどのくらい安定なのかを確認した方がいいと思っています。
StackingRegressor
スタッキングによる回帰
回帰モデルの性能を確認するため、糖尿病データを使ってみます。
from sklearn.datasets import load_diabetes
X, y = load_diabetes(return_X_y=True)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)
こちらも、ろくなパラメータチューニングしてないので改良の余地はありますが、
from sklearn.ensemble import RandomForestRegressor
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.svm import SVR
from sklearn.ensemble import StackingRegressor
from sklearn.neural_network import MLPRegressor
from sklearn.cross_decomposition import PLSRegression
estimators = [
('svr', make_pipeline(StandardScaler(), SVR())),
('rf', RandomForestRegressor()),
('mlp', MLPRegressor(max_iter=10000))
]
clf = StackingRegressor(
estimators=estimators,
final_estimator=PLSRegression(),
)
clf.fit(X_train, y_train)
clf.score(X_test, y_test)
0.4940607294168183
単独の回帰モデルの性能
比較として、単独の回帰モデルののR2値を計算してみます。
make_pipeline(StandardScaler(), SVR()).fit(X_train, y_train).score(X_test, y_test)
0.17571936903725216
RandomForestRegressor().fit(X_train, y_train).score(X_test, y_test)
0.46261715392586217
MLPRegressor(max_iter=10000).fit(X_train, y_train).score(X_test, y_test)
0.4936782755875562
PLSRegression().fit(X_train, y_train).score(X_test, y_test)
0.4927059150604132
こちらも、単独で使うよりも、組み合わせた方が良いという結果になりました。
ですが、train_test_split から計算し直すと、分割のされ方によっては単独の回帰モデルのほうが性能が良くなったりします。
性能比較には、ランダムシードを固定せずに、何度も計算を繰り返して、その性能がどのくらい安定なのかを確認した方がいいと思っています。