Task5.模型融合
把个体学习器结合在一起的时候使用的方法叫结合策略。
Stacking
-
什么是stacking:
stacking 就是当用初始训练数据学习出若干个基学习器后,将这几个学习器的预测结果作为新的训练集,来学习一个新的学习器。
-
算法示意图
引用自 西瓜书《机器学习》
-
Stacking有时对于如果训练集和测试集分布不那么一致的情况下是有一点问题的,其问题在于用初始模型训练的标签再利用真实标签进行再训练,毫无疑问会导致一定的模型过拟合训练集,这样或许模型在测试集上的泛化能力或者说效果会有一定的下降,因此现在的问题变成了如何降低再训练的过拟合性,这里我们一般有两种方法。
- 次级模型尽量选择简单的线性模型
- 利用K折交叉验证
回归\分类的概率-融合:
- 简单加权平均,结果直接融合
- mean平均
- median平均
- 回归的Stacking
分类模型融合
-
Voting投票机制,分为软投票和硬投票两种,其原理采用少数服从多数的思想。
- **硬投票:**对多个模型直接进行投票,不区分模型结果的相对重要度,最终投票数最多的类为最终被预测的类。
- **软投票:**和硬投票原理相同,增加了设置权重的功能,可以为不同模型设置不同权重,进而区别模型不同的重要度。
-
分类的Stacking\Blending
-
stacking是一种分层模型集成框架。
以两层为例,第一层由多个基学习器组成,其输入为原始训练集,第二层的模型则是以第一层基学习器的输出作为训练集进行再训练,从而得到完整的stacking模型, stacking两层模型都使用了全部的训练数据。
''' 5-Fold Stacking ''' from sklearn.ensemble import RandomForestClassifier from sklearn.ensemble import ExtraTreesClassifier,GradientBoostingClassifier import pandas as pd #创建训练的数据集 data_0 = iris.data data = data_0[:100,:] target_0 = iris.target target = target_0[:100] #模型融合中使用到的各个单模型 clfs = [LogisticRegression(solver='lbfgs'), RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=5)] #切分一部分数据作为测试集 X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.3, random_state=2020) dataset_blend_train = np.zeros((X.shape[0], len(clfs))) dataset_blend_test = np.zeros((X_predict.shape[0], len(clfs))) #5折stacking n_splits = 5 skf = StratifiedKFold(n_splits) skf = skf.split(X, y) for j, clf in enumerate(clfs): #依次训练各个单模型 dataset_blend_test_j = np.zeros((X_predict.shape[0], 5)) for i, (train, test) in enumerate(skf): #5-Fold交叉训练,使用第i个部分作为预测,剩余的部分来训练模型,获得其预测的输出作为第i部分的新特征。 X_train, y_train, X_test, y_test = X[train], y[train], X[test], y[test] clf.fit(X_train, y_train) y_submission = clf.predict_proba(X_test)[:, 1] dataset_blend_train[test, j] = y_submission dataset_blend_test_j[:, i] = clf.predict_proba(X_predict)[:, 1] #对于测试集,直接用这k个模型的预测值均值作为新的特征。 dataset_blend_test[:, j] = dataset_blend_test_j.mean(1) print("val auc Score: %f" % roc_auc_score(y_predict, dataset_blend_test[:, j])) clf = LogisticRegression(solver='lbfgs') clf.fit(dataset_blend_train, y) y_submission = clf.predict_proba(dataset_blend_test)[:, 1] print("Val auc Score of Stacking: %f" % (roc_auc_score(y_predict, y_submission)))
-
Blending,其实和Stacking是一种类似的多层模型融合的形式
其主要思路是把原始的训练集先分成两部分,比如70%的数据作为新的训练集,剩下30%的数据作为测试集。
在第一层,我们在这70%的数据上训练多个模型,然后去预测那30%数据的label,同时也预测test集的label。
在第二层,我们就直接用这30%数据在第一层预测的结果做为新特征继续训练,然后用test集第一层预测的label做特征,用第二层训练的模型做进一步预测
其优点在于:
- 1.比stacking简单(因为不用进行k次的交叉验证来获得stacker feature)
- 2.避开了一个信息泄露问题:generlizers和stacker使用了不一样的数据集
缺点在于:
- 1.使用了很少的数据(第二阶段的blender只使用training set10%的量)
- 2.blender可能会过拟合
- 3.stacking使用多次的交叉验证会比较稳健 ‘’’
''' Blending ''' #创建训练的数据集 #创建训练的数据集 data_0 = iris.data data = data_0[:100,:] target_0 = iris.target target = target_0[:100] #模型融合中使用到的各个单模型 clfs = [LogisticRegression(solver='lbfgs'), RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), #ExtraTreesClassifier(n_estimators=5, n_jobs=-1, criterion='entropy'), GradientBoostingClassifier(learning_rate=0.05, subsample=0.5, max_depth=6, n_estimators=5)] #切分一部分数据作为测试集 X, X_predict, y, y_predict = train_test_split(data, target, test_size=0.3, random_state=2020) #切分训练数据集为d1,d2两部分 X_d1, X_d2, y_d1, y_d2 = train_test_split(X, y, test_size=0.5, random_state=2020) dataset_d1 = np.zeros((X_d2.shape[0], len(clfs))) dataset_d2 = np.zeros((X_predict.shape[0], len(clfs))) for j, clf in enumerate(clfs): #依次训练各个单模型 clf.fit(X_d1, y_d1) y_submission = clf.predict_proba(X_d2)[:, 1] dataset_d1[:, j] = y_submission #对于测试集,直接用这k个模型的预测值作为新的特征。 dataset_d2[:, j] = clf.predict_proba(X_predict)[:, 1] print("val auc Score: %f" % roc_auc_score(y_predict, dataset_d2[:, j])) #融合使用的模型 clf = GradientBoostingClassifier(learning_rate=0.02, subsample=0.5, max_depth=6, n_estimators=30) clf.fit(dataset_d1, y_d2) y_submission = clf.predict_proba(dataset_d2)[:, 1] print("Val auc Score of Blending: %f" % (roc_auc_score(y_predict, y_submission)))
-
其他一些方法
1. 将特征放进模型中预测,并将预测结果变换并作为新的特征加入原有特征中再经过模型预测结果 (Stacking 变化)
(可以反复预测多次将结果加入最后的特征中)
经验总结
比赛的融合这个问题,个人的看法来说其实涉及多个层面,也是提分和提升模型鲁棒性的一种重要方法:
- 结果层面的融合,这种是最常见的融合方法,其可行的融合方法也有很多,比如根据结果的得分进行加权融合,还可以做Log,exp处理等。在做结果融合的时候,有一个很重要的条件是模型结果的得分要比较近似,然后结果的差异要比较大,这样的结果融合往往有比较好的效果提升。
- 特征层面的融合,这个层面其实感觉不叫融合,准确说可以叫分割,很多时候如果我们用同种模型训练,可以把特征进行切分给不同的模型,然后在后面进行模型或者结果融合有时也能产生比较好的效果。
- 模型层面的融合,模型层面的融合可能就涉及模型的堆叠和设计,比如加Staking层,部分模型的结果作为特征输入等,这些就需要多实验和思考了,基于模型层面的融合最好不同模型类型要有一定的差异,用同种模型不同的参数的收益一般是比较小的。
关于Datawhale:
Datawhale是一个专注于数据科学与AI领域的开源组织,汇集了众多领域院校和知名企业的优秀学习者,聚合了一群有开源精神和探索精神的团队成员。Datawhale 以“for the learner,和学习者一起成长”为愿景,鼓励真实地展现自我、开放包容、互信互助、敢于试错和勇于担当。同时 Datawhale 用开源的理念去探索开源内容、开源学习和开源方案,赋能人才培养,助力人才成长,建立起人与人,人与知识,人与企业和人与未来的联结。
本次数据挖掘路径学习,专题知识将在天池分享,详情可关注Datawhale: