zoukankan      html  css  js  c++  java
  • 模型融合

    一、Voting

    模型融合其实也没有想象的那么高大上,从最简单的Voting说起,这也可以说是一种模型融合。假设对于一个二分类问题,有3个基础模型,那么就采取投票制的方法,投票多者确定为最终的分类。

    二、Averaging

    对于回归问题,一个简单直接的思路是取平均。稍稍改进的方法是进行加权平均。权值可以用排序的方法确定,举个例子,比如A、B、C三种基本模型,模型效果进行排名,假设排名分别是1,2,3,那么给这三个模型赋予的权值分别是3/6、2/6、1/6
    这两种方法看似简单,其实后面的高级算法也可以说是基于此而产生的,Bagging或者Boosting都是一种把许多弱分类器这样融合成强分类器的思想。

    三、Bagging

    Bagging就是采用有放回的方式进行抽样,用抽样的样本建立子模型,对子模型进行训练,这个过程重复多次,最后进行融合。大概分为这样两步:

    1. 重复K次
    • 有放回地重复抽样建模
    • 训练子模型

            2.模型融合

    • 分类问题:voting
    • 回归问题:average

    Bagging算法不用我们自己实现,随机森林就是基于Bagging算法的一个典型例子,采用的基分类器是决策树。R和python都集成好了,直接调用。

    四、Boosting

    Bagging算法可以并行处理,而Boosting的思想是一种迭代的方法,每一次训练的时候都更加关心分类错误的样例,给这些分类错误的样例增加更大的权重,下一次迭代的目标就是能够更容易辨别出上一轮分类错误的样例。最终将这些弱分类器进行加权相加。


    同样地,基于Boosting思想的有AdaBoost、GBDT等,在R和python也都是集成好了直接调用。
    PS:理解了这两点,面试的时候关于Bagging、Boosting的区别就可以说上来一些,问Randomfroest和AdaBoost的区别也可以从这方面入手回答。也算是留一个小问题,随机森林、Adaboost、GBDT、XGBoost的区别是什么?

    五、Stacking

    Stacking方法其实弄懂之后应该是比Boosting要简单的,毕竟小几十行代码可以写出一个Stacking算法。我先从一种“错误”但是容易懂的Stacking方法讲起。
    Stacking模型本质上是一种分层的结构,这里简单起见,只分析二级Stacking.假设我们有3个基模型M1、M2、M3。

    1. 基模型M1,对训练集train训练,然后用于预测train和test的标签列,分别是P1,T1
    egin{pmatrix}vdots  \P_1   \vdots  \vdots  \end{pmatrix}egin{pmatrix}vdots  \T_1   \vdots  \vdots  \end{pmatrix}
    对于M2和M3,重复相同的工作,这样也得到P2,T2,P3,T3。

    2. 分别把P1,P2,P3以及T1,T2,T3合并,得到一个新的训练集和测试集train2,test2。

    egin{pmatrix}vdots  \P_1   \vdots  \vdots  \end{pmatrix}egin{pmatrix}vdots  \P_2   \vdots  \vdots  \end{pmatrix}egin{pmatrix}vdots  \P_3   \vdots  \vdots  \end{pmatrix}impliesoverbrace{egin{pmatrix}vdots &vdots  &vdots \P_1 & P_2 &P_3   \vdots  &vdots &vdots \vdots &vdots &vdots  \end{pmatrix}}^{train2}

    egin{pmatrix}vdots  \T_1   \vdots  \vdots  \end{pmatrix}egin{pmatrix}vdots  \T_2   \vdots  \vdots  \end{pmatrix}egin{pmatrix}vdots  \T_3   \vdots  \vdots  \end{pmatrix}impliesoverbrace{egin{pmatrix}vdots &vdots  &vdots \T_1 & T_2 &T_3   \vdots  &vdots &vdots \vdots &vdots &vdots  \end{pmatrix}}^{test2}


    3. 再用第二层的模型M4训练train2,预测test2,得到最终的标签列。

    overbrace{egin{pmatrix}vdots &vdots  &vdots \P_1 & P_2 &P_3   \vdots  &vdots &vdots \vdots &vdots &vdots  \end{pmatrix}}^{train2}overbrace{implies}^{train}overbrace{egin{pmatrix}vdots &vdots  &vdots \T_1 & T_2 &T_3   \vdots  &vdots &vdots \vdots &vdots &vdots  \end{pmatrix}}^{test2}overbrace{implies}^{predict}egin{pmatrix}vdots  \pred   \vdots  \vdots  \end{pmatrix}

    Stacking本质上就是这么直接的思路,但是这样肯定是不行的,问题在于P1的得到是有问题的,用整个训练集训练的模型反过来去预测训练集的标签,毫无疑问过拟合是非常非常严重的,因此现在的问题变成了如何在解决过拟合的前提下得到P1、P2、P3,这就变成了熟悉的节奏——K折交叉验证。我们以2折交叉验证得到P1为例,假设训练集为4行3列

    egin{pmatrix}a_{11} & a_{12} &a_{13}  \a_{21} & a_{22} &a_{23}  \a_{31} & a_{32} &a_{33}  \a_{41} & a_{42} &a_{43}  \end{pmatrix}

    将其划分为2部分

    overbrace{egin{pmatrix}a_{11} & a_{12} &a_{13}  \a_{21} & a_{22} &a_{23}  \end{pmatrix}}^{traina}

    overbrace{egin{pmatrix}a_{31} & a_{32} &a_{33}  \a_{41} & a_{42} &a_{43}  \end{pmatrix}}^{trainb}

    用traina训练模型M1,然后在trainb上进行预测得到preb3和pred4
    overbrace{egin{pmatrix}a_{11} & a_{12} &a_{13}  \a_{21} & a_{22} &a_{23}  \end{pmatrix}}^{traina}overbrace{implies}^{train}overbrace{egin{pmatrix}a_{31} & a_{32} &a_{33}  \a_{41} & a_{42} &a_{43}  \end{pmatrix}}^{trainb}overbrace{implies}^{predict}egin{pmatrix}pred3  \pred4   \end{pmatrix}
    在trainb上训练模型M1,然后在traina上进行预测得到pred1和pred2
    overbrace{egin{pmatrix}a_{31} & a_{32} &a_{33}  \a_{41} & a_{42} &a_{43}  \end{pmatrix}}^{trainb}overbrace{implies}^{train}overbrace{egin{pmatrix}a_{11} & a_{12} &a_{13}  \a_{21} & a_{22} &a_{23}  \end{pmatrix}}^{traina}overbrace{implies}^{predict}egin{pmatrix}pred1  \pred2   \end{pmatrix}
    然后把两个预测集进行拼接
    egin{pmatrix}pred1  \pred2   \end{pmatrix}+egin{pmatrix}pred3  \pred4   \end{pmatrix}=egin{pmatrix}pred1  \pred2   \pred3  \pred4   \end{pmatrix}=egin{pmatrix}vdots  \P_1   \vdots  \vdots  \end{pmatrix}
    对于测试集T1的得到,有两种方法。注意到刚刚是2折交叉验证,M1相当于训练了2次,所以一种方法是每一次训练M1,可以直接对整个test进行预测,这样2折交叉验证后测试集相当于预测了2次,然后对这两列求平均得到T1。
    或者直接对测试集只用M1预测一次直接得到T1。
    P1、T1得到之后,P2、T2、P3、T3也就是同样的方法。理解了2折交叉验证,对于K折的情况也就理解也就非常顺利了。所以最终的代码是两层循环,第一层循环控制基模型的数目,每一个基模型要这样去得到P1,T1,第二层循环控制的是交叉验证的次数K,对每一个基模型,会训练K次最后拼接得到P1,取平均得到T1。

    class StackingAveragedModels (BaseEstimator, RegressorMixin, TransformerMixin):
        def __init__(self, base_models, meta_model, n_folds=5):
            self.base_models = base_models
            self.meta_model = meta_model
            self.n_folds = n_folds
    
        # We again fit the data on clones of the original models
        def fit(self, X, y):
            self.base_models_ = [list () for x in self.base_models]
            self.meta_model_ = clone(self.meta_model)
            kfold = KFold(n_splits=self.n_folds, shuffle=True, random_state=156)
    
            # 使用K-fold的方法来进行交叉验证,将每次验证的结果作为新的特征来进行处理
            out_of_fold_predictions = np.zeros((X.shape[0], len(self.base_models)))
            for i, model in enumerate(self.base_models):
                for train_index, holdout_index in kfold.split(X, y):
                    instance = clone(model)
                    self.base_models_[i].append(instance)
                    instance.fit(X[train_index],  y[train_index])
                    y_pred = instance.predict(X[holdout_index])
                    out_of_fold_predictions[holdout_index, i] = y_pred
    
            # 将交叉验证预测出的结果 和 训练集中的标签值进行训练
            self.meta_model_.fit(out_of_fold_predictions, y)
            return self
    
        # 从得到的新的特征  采用新的模型进行预测  并输出结果
        def predict(self, X):
            meta_features = np.column_stack ([
                np.column_stack([model.predict (X) for model in base_models]).mean (axis=1)
                for base_models in self.base_models_])
            return self.meta_model_.predict(meta_features)
    
    stacked_averaged_models = StackingAveragedModels(base_models=(ENet, GBoost, KRR), meta_model=lasso)
    
  • 相关阅读:
    N皇后问题
    iPhone中自绘实现步骤
    ObjectiveC利用协议实现回调函数
    iphone实现双缓冲
    JAVA_内部类
    JAVA_ArrayList
    Ant入门
    JAVA_两种比较器的实现
    JAVA_继承内部类
    JAVA_序列化和反序列化
  • 原文地址:https://www.cnblogs.com/USTC-ZCC/p/11115087.html
Copyright © 2011-2022 走看看