美文网首页
Stacking的思路及编码

Stacking的思路及编码

作者: SeekerLinJunYu | 来源:发表于2019-04-23 15:27 被阅读0次

     在kaggle上打比赛的时候发现,利用ensemble的思路对Base model进行集成是一个对最终模型影响较大的环节,能够有效提升分数,同时还能降低overfitting的风险.
     Ensemble思路包括以下几种:

    • Bagging: 用不同的训练数据集的随机子集来对指定个数的Base Model进行训练,最后决策由每个Base Model投票决定.典型应用如名头响亮的随机森林Random Forest.
    • Boosting: 相比 bagging,Boosting的思路更加复杂一些.基本的思路在于迭代训练Base Model,每一轮迭代出的新模型都是基于上一代模型所犯错误修正得来,手段在于加重错误样本的权重.典型应用诸如AdaBoostGradient Boosting等.通常来说,相比Bagging会有更好的效果,但是也是更加容易overfitting的.
    • Blending: 使用不相交的数据训练(无放回采样,bootstrap=False)出不同的Base Model,然后将输出结果进行加权平均.
    • stacking: 相比其他的Ensemble模型,stacking选择了全新的思路.不再直接聚合所有预测器的结果,而是直接利用Base Model的预测结果作为数据源来训练一个更高层次(我也不知道这么描述对不对 :-)的模型.

    Stacking的详解:

     根据在kaggle上的经验,Stacking方法相比其他的方法往往能取得更好的一个效果(不知道是不是我以偏概全了 :-).

    1. 关于Stacking的思路
       正如上面所说,stacking的思想在于直接利用Base Model(Layer_1)的预测结果作为更高层次模型(Layer_2,....Layer_n)的训练集.
      下图清晰地展示了这一思路.Blending指的是根据Prediction训练出高层模型(通常称为metal learner 或者 blender)后进行的预测操作.


      Stacking的简单思路图.png
    2. Stacking应用技巧
       在使用Stacking时,如果直接把所有的数据全都喂给Base Model当然是一种很不正确的操作,这会导致严重的过拟合.因此为了高效使用Stacking,通常的做法是使用交叉验证的思路对数据集进行拆分,然后分别训练Base Model.
       在拆分时会留下其中1份(hold-out-set)用来做预测.预测结果是由Base Model预测所得,结果需要保存下来留作第二层的训练使用.在这样一个迭代训练的过程中,每个模型都将被训练n次(n = cv,即交叉验证的折数),做n次预测,将n次预测的结果拼接起来就是一列完整的预测数据.最终我们就可以得到一个训练集行数 * Base Model数量的矩阵,这个矩阵就会作为第二层Model的训练数据. 第二层Model训练完成后,将每个Base Model对测试数据(不同于hold-out-set)的预测拿来让它进行预测,就可以得到最后的输出.

    kaggle-guide-stacking-diagram.jpg

     以上都还只是两层的Stacking,也就是说还能构造三层 . 四层 甚至五层的stacking.


    image.png
    1. 以下是实现代码,并给出了我的注解,方便阅读
    class Ensemble(object):
        def __init__(self, n_folds, stacker, base_models):
            self.n_folds = n_folds
            self.stacker = stacker               # 将要创建的二层stacker堆叠器
            self.base_models = base_models
    
        def fit_predict(self, X, y, T):        
            X = np.array(X)              # 训练集
            y = np.array(y)
            T = np.array(T)              # 测试集
            
             # 创建交叉验证对象fold
            folds = list(KFold(len(y), n_folds=self.n_folds, shuffle=True, random_state=2016))
    
            # 创建第二层训练集  
            S_train = np.zeros((X.shape[0], len(self.base_models)))  
            #  创建第二层测试集
            S_test = np.zeros((T.shape[0], len(self.base_models)))
    
            # 循环生成S_train 和 S_test 
            for i, clf in enumerate(self.base_models):          # 外层遍历每一个base_model
                S_test_i = np.zeros((T.shape[0], len(folds)))    # 初始化每一个模型的预测集
    
                for j, (train_idx, test_idx) in enumerate(folds):    # 内层遍历每一份hold-one-out数据
                    X_train = X[train_idx]                      # 交叉验证下的训练集
                    y_train = y[train_idx]
                    X_holdout = X[test_idx]                  # 交叉验证下的hold-one-out数据
                    # y_holdout = y[test_idx]
                    clf.fit(X_train, y_train)                  # 训练拟合
                    y_pred = clf.predict(X_holdout)[:]         # 拿到hold-one-out上的预测结果
                    S_train[test_idx, i] = y_pred              # 放入二层训练集S_train中
                    S_test_i[:, j] = clf.predict(T)[:]         # 拿到二层测试集
               
                # 因为每个模型都会被训练并预测测试集n_fold次,为了保证二层测试集与训练集同规模,需要对其取均值
                S_test[:, i] = S_test_i.mean(1)     
           
            self.stacker.fit(S_train, y)                      # 二层stacker堆叠器训练
            y_pred = self.stacker.predict(S_test)[:]          # 拿到最终的预测结果
            return y_pred
    

    参考自 https://dnc1994.com/2016/04/rank-10-percent-in-first-kaggle-competition/

    相关文章

      网友评论

          本文标题:Stacking的思路及编码

          本文链接:https://www.haomeiwen.com/subject/ikevgqtx.html