Stackingについて

https://mlwave.com/kaggle-ensembling-guide/

を読んでも意味がわからなかったけど、やっとわかったのでメモとして残す。

意味がわからなかったのは、Stacked generalizationの部分で、

・Split the train set in 2 parts: train_a and train_b
・Fit a first-stage model on train_a and create predictions for train_b
・Fit the same model on train_b and create predictions for train_a
・Finally fit the model on the entire train set and create predictions for the test set.
・Now train a second-stage stacker model on the probabilities from the first-stage model(s).

訳してみると

・学習データをtrain_aとtrain_bの2つに分ける
・first-stageモデルをtrain_aで学習させ、train_bの予測をする
・同じモデルをtrain_bで学習させ、train_aの予測をする
・最後に、学習データ全体でモデルを学習させ、テストデータの予測をする
・ここで、second-stage stackerモデルをfirst-stageモデルから得られた確率で学習させる

で、とくに最後の"Now train a second-stage stacker model on the probabilities from the first-stage model(s)."が何を言っているのかさっぱりわからなかった。

https://www.kaggle.com/rcasellas/ensemble-stacking-with-et-script/codehttps://github.com/MLWave/Kaggle-Ensemble-Guide/blob/master/blend_proba.py をみたらなんとなく理解できた

身長と体重から男か女かを求める、みたいな問題を考える。

学習データとして6人分の身長体重と男か女かが与えられ、テストデータとして3人分の身長体重が与えられたとしよう。

x_train = np.array([[170, 64], [158, 49], [162, 53], [165, 58], [149, 50], [178, 80]])
y_train = np.array([1, 0, 0, 1, 0, 1]) # 1: 男性, 0:女性
x_test = np.array([[181, 83], [168, 52], [170, 60]])

x_trainとy_trainでなんらかのモデルを学習させてx_testをそのモデルに渡せばx_testのそれぞれが男なのか女なのか?の予測をしてはくれるが、ここでやりたいのは、複数のモデルを組み合わせてより精度の良い予測をすることである。(実際にモデルを組み合わせたからといって必ず精度が良くなるわけではない)

SVCとLogisticRegressionを組み合わせてみる

from sklearn.svm import SVC
from sklearn.linear_model import LogisticRegression

model_svc = SVC(C=0.025, kernel='linear', probability=True)
model_lr = LogisticRegression(C=1e5)

それぞれのモデルで、

1. 3~6人目のデータでモデルを学習させ、1人目と2人目の予測値を出す
2. 1,2,5,6人目のデータでモデルを学習させ、3人目と4人目の予測値を出す
3. 1~4人目のデータでモデルを学習させ、5人目と6人目の予測値を出す

という作業をまず行う

# 3~6人目のデータで学習し、1人目と2人目を予測する
train_idx = [2,3,4,5]
test_idx=[0,1]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.43256083,  0.56743917],
       [ 0.60936777,  0.39063223]])

# 1,2,5,6人目のデータで学習し、3人目と4人目を予測する
train_idx = [0,1,4,5]
test_idx=[2,3]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.57525104,  0.42474896],
       [ 0.5       ,  0.5       ]])

# 1~4人目のデータで学習し、5人目と6人目を予測する
train_idx = [0,1,2,3]
test_idx=[4,5]
model_svc.fit(x_train[train_idx], y_train[train_idx])
model_svc.predict_proba(x_train[test_idx])

=> array([[ 0.82079699,  0.17920301],
       [ 0.04084148,  0.95915852]])



これが、

・学習データをtrain_aとtrain_bの2つに分ける
・first-stageモデルをtrain_aで学習させ、train_bの予測をする
・同じモデルをtrain_bで学習させ、train_aの予測をする

の作業に相当する。この結果、SVCでは、

[0.43256083, 0.60936777, 0.57525104, 0.5, 0.82079699, 0.0408414]

という結果が得られたことになる

同様の作業をLinearRegressionでも行うと、

[0.0, 1.0, 9.99998480e-01,  9.30289544e-01, 0.95117108, 0.0]

という結果が得られる

これらを組み合わせると、

[ 
  [0.43256083, 0.0],
  [0.60936777, 1.0],
  [0.57525104, 9.99998480e-01],
  [0.5,        9.30289544e-01],
  [0.82079699, 0.95117108],
  [0.0408414,  0.0]
]

というデータを作ることができる。

・Now train a second-stage stacker model on the probabilities from the first-stage model(s).

がいうところのthe probabilities from the first-stage model(s)がこのデータに相当する。

これを学習データとして、男か女か?を判断してみようというのがstackingの肝なんだと思う。
今回はこのデータを学習させるのもSVCをとりあえず使った。

st_train = np.array([ 
  [0.43256083, 0.0],
  [0.60936777, 1.0],
  [0.57525104, 9.99998480e-01],
  [0.5,        9.30289544e-01],
  [0.82079699, 0.95117108],
  [0.0408414,  0.0]
])
model_svc_for_stack = SVC(C=0.025, kernel='linear', probability=True)
model_svc_for_stack.fit(st_train, y_train)

このモデルに、テストデータを渡してpredictを実行したいけどテストデータは身長と体重の形式なので渡せるデータに変換しなければならない。

そこで

・Finally fit the model on the entire train set and create predictions for the test set.

の作業が必要になる。

model_svc.fit(x_train, y_train)
model_svc.predict_proba(x_test)

=> array([[ 0.08281354,  0.91718646],
       [ 0.56683773,  0.43316227],
       [ 0.4093662 ,  0.5906338 ]])

model_lr.fit(x_train, y_train)
model_lr.predict_proba(x_test)

=> array([[  0.00000000e+00,   1.00000000e+00],
       [  1.00000000e+00,   4.45860798e-19],
       [  1.20908600e-05,   9.99987909e-01]])

よって

[ [0.08281354, 0.0],
  [0.56683773, 1.0],
  [0.4093662, 1.20908600e-05]
]

を先ほどのmodel_svc_for_stackに渡してやれば、最終的な予測を行うことができる

st_test = np.array([ [0.08281354, 0.0],
  [0.56683773, 1.0],
  [0.4093662, 1.20908600e-05]])

model_svc_for_stack.predict_proba(st_test)
=> array([[ 0.4850637 ,  0.5149363 ],
       [ 0.50555437,  0.49444563],
       [ 0.48761824,  0.51238176]])

話としては以上。

以下補足。

補足1

https://www.kaggle.com/rcasellas/ensemble-stacking-with-et-script/code
では、st_testを作るのに、"# 1,2,5,6人目のデータで学習し、3人目と4人目を予測する"とかで得られたそれぞれのモデルでx_testを予測してその平均を使ってた

補足2

http://qiita.com/TomHortons/items/2a05b72be180eb83a204
とかだと、たぶんst_trainとy_trainでもう1回今回でいうところのmodel_svcとmodel_lrを使ってst_train_2的なデータを作ったうえで、それをxgbでまとめているみたい