模型融合Stacking

简介

最近在尝试做一下Kaggle上的Titanic和房价预测例子,练练手。到了模型融合这一步,不理解Stacking具体的做法。看了几篇博文。

转载:

以Titanic为例

以Kaggle的Titanic(泰坦尼克预测)入门比赛来讲解stacking的应用(两层)。

数据的行数:train.csv有890行,也就是890个人,test.csv有418行(418个人)。而数据的列数就看你保留了多少个feature了,因人而异。我自己的train保留了 7+1(1是预测列)。

在网上为数不多的stacking内容里,相信你早看过了这张图:

对于每一轮的5-fold,Model 1都要做满5次的训练和预测。上半部分是用一个基础模型进行5折交叉验证,如:用XGBoost作为基础模型Model1,5折交叉验证就是先拿出四折作为training data,另外一折作为testing data。注意:在stacking中此部分数据会用到整个traing set。

每一次的交叉验证包含两个过程,

  1. 基于training data训练模型;
  2. 基于training data训练生成的模型对testing data进行预测。

Titanic的Train Data有890行。(请对应图中的上层部分)每1次的fold,都会生成712行小train,178行小test。我们用Model 1来训练712行的小train,然后预测178行小test。预测的结果是长度为178的预测值。这样的动作走5次! 长度为178的预测值x5=890预测值,刚好和Train data长度吻合。这个890预测值是Model 1产生的,我们先存着,因为,一会让它将是第二层模型的训练来源。

重点:这一步产生的预测值我们可以转成890x1(890 行,1列),记作 P1。

接着说Test Data有418行。(请对应图中的下层部分,对对对,绿绿的那些框框)每1次的fold,713行小train训练出来的Model 1要去预测我们全部的Test Data(全部!因为Test Data没有加入5-fold,所以每次都是全部)。此时,Model 1的预测结果是长度为418的预测值。这样的动作走5次!我们可以得到一个 5x418 的预测值矩阵。然后我们根据行来求平均值,最后得到一个1x418的平均预测值。

重点:这一步产生的预测值我们可以转成418x1(418行,1列),记作 p1。

走到这里,你的第一层的Model 1完成了它的使命。第一层还会有其他Model的,比如Model 2,同样的走一遍, 我们有可以得到890x1(P2)和418x1(p2)列预测值。

这样吧,假设你第一层有3个模型,这样你就会得到:来自5-fold的预测值矩阵890x3,(P1,P2,P3)和 来自Test Data预测值矩阵418x3,(p1,p2,p3)。

到第二层了。来自5-fold的预测值矩阵890x3作为你的Train Data,有的会将这三列作为特征列拼接在原来的特征矩阵中,训练第二层的模型。来自Test Data预测值矩阵418x3就是你的Test Data,用训练好的模型来预测他们吧。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Out-of-fold Predictions
ntrain = train.shape[0] # 891
ntest = test.shape[0] # 418
kf = KFold(n_split=5, random_state=2017)

def get_oof(clf, X_train, y_train, X_test):
oof_train = np.zeros((ntrain, )) # 1x890
oof_test = np.zeros((ntest, )) # 1x418
oof_test_skf = np.empty((5, ntest)) # 5x418

for i, (train_index, test_index) in enumerate(kf.split(X_train)):
kf_X_train = x_train[train_index] # 712x7
kf_y_train = y_train[train_index] # 712x1
kf_X_test = X_train[test_index]

clf.train(kf_X_train, kf_y_train)

oof_train[test_index] = clf.predict(kf_X_test) # 1x178 =====> will be 1x890 after 5 folds
oof_test_skf[i, :] = clf.predict(X_test) # 1x418

oof_test[:] = oof_test_skf.mean(axis=0) # 1x418
return oof_train.reshape(-1, 1), oof_test.reshape(-1, 1)
一分一毛,也是心意。