机器学习之模型融合(详解Stacking,Blending)

╄→尐↘猪︶ㄣ 提交于 2020-01-16 21:10:07

集成学习和多模型融合的区别
集成学习是指多个弱分类器(子模型)集成为强分类器,这种弱分类器是同质的分类器,比如GBDT,Adaboost,RF等。

  • 根据弱分类器之间的关系,可以分为相关(第i个弱分类器依赖于第i-1个弱分类器)和独立(每个弱分类器相互独立)。相关的话,只能串行实现,主要是降低bias(偏差);独立的话,可以并行实现,主要是降低variance(方差)

多模型融合是多个分类器,这些分类器是异构的,各模型解决不同的局部问题,多模型融合一般用来做信息补充和互补

Ensemble Generation

常见模型融合的方法

boosting

迭代训练某个基本模型:根据第i-1轮预测错误得到的情况来修改第i轮训练样本的权重,比较容易过拟合。

bagging

这是一种少数服从多数的思想,通过训练集中不同的子集训练不同的子模型,最后对每个子模型进行投票。

Stacking

层次融合的思想,第一层用多个基本模型,然后将多个基本模型的结果作为第二层的输入,第二层一般用LR进行训练(这么做主要是为了匹配每个基本模型的权重)。

blending

层次融合的思想,使用不相交的数据,将样本集分为训练集train和测试集test,再将训练集train数据划分为两部分(d1,d2),用对d1训练的模型去预测d2和test。用上一轮d2的预测值和标签训练新的分类器,然后把test的new features输入作为最终的预测值。

各种模型融合的区别

Bagging,Boosting二者之间的区别

(1) 样本选择:

  • Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
  • Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化,而权值是根据上一轮的分类结果进行调整。

(2) 样例权重:

  • Bagging:使用均匀取样,每个样例的权重相等
  • Boosting:根据错误率不断调整样例的权重,错误率越大则权重越大

(3) 预测函数:

  • Bagging:所有预测函数的权重相等。
  • Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。

(4) 并行计算:

  • Bagging:各个预测函数可以并行生成
  • Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。

Stacking,Blending二者之间的区别

Blending方式和Stacking方式很类似,相比Stacking更简单点,两者的区别是:
(1) blending是直接准备好一部分10%留出集只在留出集上继续预测,用不相交的数据训练不同的Base Model,将它们的输出取(加权)平均,blending实现简单,但对训练数据利用少了。
(2) stacking使用多折交叉验证,比使用单一留出集更加稳健。
blending和stacking都挺好的,可以根据偏好进行选择,可以一部分做blending,一部分做stacking。

Stacking与blending详解及代码

Stacking的两种思想

第一种思想:
stacking的思想
假设有12000条数据样本,将样本集分为训练集(training data)10000条和测试集(testing data)2000条。
第一层: 采用4个模型(假设其分别是RF、ET、GBDT、XGB),分别对训练集进行训练,然后将预测的结果作为下一层的输入。
Step1:将训练集分为5折
1. 分别用第2、3、4、5折训练一个RF,用训练好的RF直接预测第1折训练数据;
2. 分别用第1、3、4、5折训练一个新的RF,用训练好的RF直接预测第2折训练数据;
3. 分别用第1、2、4、5折训练一个新的RF,用训练好的RF直接预测第3折训练数据;
4. 分别用第1、2、3、5折训练一个新的RF,用训练好的RF直接预测第4折训练数据;
5. 分别用第1、2、3、4折训练一个新的RF,用训练好的RF直接预测第5折训练数据;
训练后,可以得到100001维的RF对training data的预测结果,对于testing data,用上面训练得到的5个RF,预测出20005维的预测结果,然后对其取平均,20001维的RF预测结果。
Step2:另外3个模型同理。
最终第一层中,training data会输出10000
4维的预测结果,将这个结果作为第二层训练集的输入。testing data 会输出2000*4维的结果,将这个结果作为第二层预测集的输入。
第二层: 将上一层的结果带入新的模型中,进行训练再预测,第二层的模型一般为了防止过拟合会采用简单的模型。

第二种思想: 第二层的输入数据,除了第一层的训练结果外,还包括了原始特征。
在这里插入图片描述

'''
Stacking的实现案例
'''
from sklearn.ensemble import RandomForestClassifier,ExtraTreesClassifier,GradientBoostingClassifier
from sklearn.cross_validation import train_test_split
from sklearn.cross_validation import StratifiedKFold
import numpy as np
from sklearn.metrics import roc_auc_score
from sklearn.datasets.samples_generator import make_blobs

'''创建训练的数据集'''
data, target = make_blobs(n_samples=50000, centers=2, random_state=0, cluster_std=0.60)

'''模型融合中使用到的各个单模型'''
clfs = [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.33, random_state=2017)

dataset_blend_train = np.zeros((X.shape[0], len(clfs)))
dataset_blend_test = np.zeros((X_predict.shape[0], len(clfs)))

'''5折stacking'''
n_folds = 5
skf = list(StratifiedKFold(y, n_folds))

for j,clf in enumerate(clfs):
    '''依次训练各个单模型'''
    dataset_blend_test_j = np.zeros((X_predict.shape[0], len(skf)))
    for i, (train, test) in enumerate(skf):
        '''使用第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]
    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 = GradientBoostingClassifier(learning_rate=0.02,subsample=0.5,max_depth=6,n_estimators=30)
clf.fit(dataset_blend_train,y)
y_submission = clf.predict_proba(dataset_blend_test)[:,1]

print("Linear stretch of predictions to [0,1]")
y_submission = (y_submission - y_submission.min())/(y_submission.max()-y_submission.min())
print("blend result")
print(roc_auc_score(y_predict,y_submission))

Blending与stacking类似,只是将Kfold CV改变为了HoldOut CV,也就是原来的K折交叉验证是等距划分训练集,HoldOut CV是根据自己定义的百分比进行训练集测试集的划分。

'''blending'''
from sklearn.ensemble import RandomForestClassifier,ExtraTreesClassifier,GradientBoostingClassifier
from sklearn.cross_validation import train_test_split
from sklearn.cross_validation import StratifiedKFold
import numpy as np
from sklearn.metrics import roc_auc_score
from sklearn.datasets.samples_generator import make_blobs

'''创建训练的数据集'''
data,target = make_blobs(n_samples=50000,centers=2,random_state=0,cluster_std=0.6)

'''模型融合中使用到的各个单模型'''
clfs= [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.33,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_d2 = np.zeros((X_d2.shape[0],len(clfs)))
dataset_predict = 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_d2[:,j] = y_submission
    '''对于测试集,直接用这k个模型的预测值作为新的特征'''
    dataset_predict[:,j] = clf.predict_proba(X_predict)[:,1]
    print("val auc Score: %f" % roc_auc_score(y_predict,dataset_predict[:,j]))

'''融合使用的模型'''
clf = GradientBoostingClassifier(learning_rate=0.02,subsample=0.5,max_depth=6,n_estimators=30)
clf.fit(dataset_d2,y_d2)
y_submission = clf.predict_proba(dataset_predict)[:,1]

print("Linear stretch of predictions to [0,1]")
y_submission = (y_submission - y_submission.min())/(y_submission.max()-y_submission.min())
print("blend result")
print("val auc Score: %f"%(roc_auc_score(y_predict,y_submission)))

【参考资料】

  1. 多模型融合和集成学习的区别和联系是什么?
  2. 机器学习模型融合
  3. ensemble之stacking详解以及Python代码实现
  4. 详解stacking过程
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!