【機械学習】スタッキングのキホンを勉強したのでそのメモ - verilog書く人の続きです。
実践、モデルのバリデーションなどについてです 。
ややこしいスタッキングですが、実装例は例えばこれ(
vertebral/stacked_generalization.py at master · log0/vertebral · GitHub
)とかがあり、参考にすれば実行できます。
しかしスタッキングされたモデル自体がscikit-learnのモデルと同じインターフェイスを持ってるほうがscikit-learnを普段使いしている人にはさっと試しやすいのではないかと思い、自分でも実装しました。
使用例
sklearnのirisデータセットで回帰します。スクリプトは(
stacked_generalization/cross_validation_for_iris.py at master · fukatani/stacked_generalization · GitHub
)にあります。
from sklearn import datasets
from sklearn.utils.validation import check_random_state
from stacked_generalization.lib.stacking import StackedClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import ExtraTreesClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.neighbors import KNeighborsClassifier
from sklearn.linear_model import LogisticRegression, RidgeClassifier
from sklearn.cross_validation import StratifiedKFold
from sklearn.manifold import TSNE
iris = datasets.load_iris()
rng = check_random_state(0)
perm = rng.permutation(iris.target.size)
iris.data = iris.data[perm]
iris.target = iris.target[perm]
bclf = LogisticRegression(random_state=1)
clfs = [RandomForestClassifier(n_estimators=40, criterion = 'gini', random_state=1),
ExtraTreesClassifier(n_estimators=30, criterion = 'gini', random_state=3),
GradientBoostingClassifier(n_estimators=25, random_state=1),
GradientBoostingClassifier(n_estimators=30, random_state=2),
KNeighborsClassifier(),
RidgeClassifier(random_state=1),
TSNE(n_components=2)
]
sc = StackedClassifier(bclf,
clfs,
n_folds=3,
verbose=0,
stack_by_proba=True,
oob_score_flag=True,
)
gb = GradientBoostingClassifier(n_estimators=25, random_state=1)
sc_score = 0
gb_score = 0
n_folds = 3
for train_idx, test_idx in StratifiedKFold(iris.target, n_folds):
xs_train = iris.data[train_idx]
y_train = iris.target[train_idx]
xs_test = iris.data[test_idx]
y_test = iris.target[test_idx]
sc.fit(xs_train, y_train)
print('oob_score: {0}'.format(sc.oob_score_))
sc_score += sc.score(xs_test, y_test)
gb.fit(xs_train, y_train)
gb_score += gb.score(xs_test, y_test)
sc_score /= n_folds
print('Stacked Classfier score: {0}'.format(sc_score))
gb_score /= n_folds
print('Gradient Boosting Classfier score: {0}'.format(gb_score))
気になる正解率
上記スクリプトの実行結果↓
Stacked Classfier score: 0.9596%
Gradient Boosting Classfier score: 0.9530%
ちょびっと…あがり…まし…た
とはいえ、結構色々なスタッキングの組み合わせを試しておりまして、下手するとステージ0の一番いいモデルよりスコアが下がっちゃうことも有り得ます。むずかすい。
以下、細かいTips
スタッキングモデルのバリデーション
クロスバリデーションをすればよいっちゃよいですが、(
【機械学習】スタッキングのキホンを勉強したのでそのメモ - verilog書く人
)で見たとおりステージ0の学習の段階で既にクロスバリデーションを行っているので、スタッキングモデル全体にクロスバリデーションすると、すべてのステージ0の学習機にn_fold*n_fold回の学習を行うことになります。
そうではなく、ステージ1にのみにクロスバリデーションを適用する方法があります[
https://arxiv.org/pdf/0911.0460.pdf
]。
私版のスタッキングはoob_score_を呼び出して計算することが可能です。scikit-learnのランダムフォレストと同様。
分類問題でのステージ0の出力(=ステージ1の入力)
voting型のアンサンブルでは、hard型とsoft型が選択できます。
どうちがうのかというと、hardでは各モデルによって単純に所属する確率が高いと判断されたクラスの多数決を取るのに対し、softでは予測確率を平均します。
スタッキングの場合も、各ステージ0がもっとも所属する確率が高いと判定したクラスのみを出力してステージ1に入力するhardと、各クラスに対する所属確率を出力させるのと、両方が考えらます。(vertebral/stacked_generalization.py at master · log0/vertebral · GitHub)なんかは後者のみ実装されていますが。
とりあえず私実装では両方選べるようにしました。
今後は、ステージ0の構成を変えられる賢いグリッドサーチとか、ステージ0のモデルごとに入力データを変えるとか、ブレンドデータのマネジメントとかいろいろしたいですが、、時間があれば。