集成学习和多模型融合的区别
集成学习是指多个弱分类器(子模型)集成为强分类器,这种弱分类器是同质的分类器,比如GBDT,Adaboost,RF等。
- 根据弱分类器之间的关系,可以分为相关(第i个弱分类器依赖于第i-1个弱分类器)和独立(每个弱分类器相互独立)。相关的话,只能串行实现,主要是降低bias(偏差);独立的话,可以并行实现,主要是降低variance(方差)
多模型融合是多个分类器,这些分类器是异构的,各模型解决不同的局部问题,多模型融合一般用来做信息补充和互补。
迭代训练某个基本模型:根据第i-1轮预测错误得到的情况来修改第i轮训练样本的权重,比较容易过拟合。
这是一种少数服从多数的思想,通过训练集中不同的子集训练不同的子模型,最后对每个子模型进行投票。
层次融合的思想,第一层用多个基本模型,然后将多个基本模型的结果作为第二层的输入,第二层一般用LR进行训练(这么做主要是为了匹配每个基本模型的权重)。
层次融合的思想,使用不相交的数据,将样本集分为训练集train和测试集test,再将训练集train数据划分为两部分(d1,d2),用对d1训练的模型去预测d2和test。用上一轮d2的预测值和标签训练新的分类器,然后把test的new features输入作为最终的预测值。
(1) 样本选择:
(2) 样例权重:
(3) 预测函数:
(4) 并行计算:
Blending方式和Stacking方式很类似,相比Stacking更简单点,两者的区别是:
(1) blending是直接准备好一部分10%留出集只在留出集上继续预测,用不相交的数据训练不同的Base Model,将它们的输出取(加权)平均,blending实现简单,但对训练数据利用少了。
(2) stacking使用多折交叉验证,比使用单一留出集更加稳健。
blending和stacking都挺好的,可以根据偏好进行选择,可以一部分做blending,一部分做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会输出100004维的预测结果,将这个结果作为第二层训练集的输入。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)))
【参考资料】