模型融合
介绍:模型融合通常可以在各种不同的机器学习任务中使结果获得提升。顾名思义,模型融合就是综合考虑不同模型的情况,并将它们的结果融合到一起。具体内容会从以下几个方面来讲:
1、Voting
2、Averaging
3、Ranking
4、Bagging
5、Boosting
6、Stacking
7、Blending
一、Voting
Voting即投票机制,分为软投票和硬投票两种,其原理采用少数服从多数的思想。
硬投票:对多个模型直接进行投票,最终投票数最多的类为最终被预测的类。
软投票:和硬投票原理相同,增加了设置权重的功能,可以为不同模型设置不同权重,进而区别模型不同的重要度。
备注:此方法用于解决分类问题。
代码实例如下:
硬投票:
iris = datasets.load_iris() x=iris.data y=iris.target x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3) clf1 = XGBClassifier(learning_rate=0.1, n_estimators=140, max_depth=1, min_child_weight=2, gamma=0, subsample=0.7, colsample_bytree=0.6, objective='binary:logistic', nthread=4, scale_pos_weight=1) clf2 = RandomForestClassifier(n_estimators=50, max_depth=1, min_samples_split=4, min_samples_leaf=54,oob_score=True) clf3 = SVC(C=0.1, probability=True) # 硬投票 eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='hard') for clf, label in zip([clf1, clf2, clf3, eclf], ['XGBBoosting', 'Random Forest', 'SVM', 'Ensemble']): scores = cross_val_score(clf, x, y, cv=5, scoring='accuracy') print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
软投票:
x=iris.data y=iris.target x_train,x_test,y_train,y_test=train_test_split(x,y,test_size=0.3) clf1 = XGBClassifier(learning_rate=0.1, n_estimators=140, max_depth=1, min_child_weight=2, gamma=0, subsample=0.7, colsample_bytree=0.6, objective='binary:logistic', nthread=4, scale_pos_weight=1) clf2 = RandomForestClassifier(n_estimators=50, max_depth=1, min_samples_split=4, min_samples_leaf=54,oob_score=True) clf3 = SVC(C=0.1, probability=True) # 软投票 eclf = VotingClassifier(estimators=[('xgb', clf1), ('rf', clf2), ('svc', clf3)], voting='soft', weights=[2, 1, 1]) clf1.fit(x_train, y_train)
二、Averaging
Averaging,其原理是对模型结果取平均。
处理回归问题,直接取平均值作为最终的预测值。(也可以使用加权平均)
平均法存在问题就是如果不同回归方法的预测结果波动幅度相差比较大,那么波动小的回归结果在融合时候起的作用就比较小。
三、Ranking
Ranking的思想和Averaging一致,但是因为上述平均法存在一定的问题。
所以这里采用了把排名做平均,如果有权重,则求n个模型权重比排名之和,即为最后的结果。
四、Bagging
Bagging方法的出现,可以完美地解决了决策树过拟合的问题,同时bagging的使用也会使分类器分类效果得到了显著的提高。
应用场景:对不稳定的分类器做Bagging是一个好主意。在机器学习中,如果训练数据的一个小变化导致学习中的分类器的大变化,则该算法(或学习算法)被认为是不稳定的。
Bagging就是采用有放回的方式进行抽样,用抽样的样本建立子模型,对子模型进行训练,这个过程重复多次,最后进行融合。大概分为两步:
1.重复K次
有放回地重复抽样建模
训练子模型
2.模型融合
模型融合,如果是分类问题用voting解决 。如果是回归问题用average解决。
注意:在bagging集成中,各个模型的预测不会彼此依赖。Bagging算法不用我们自己实现,随机森林就是基于Bagging算法的一个典型例子,采用的基分类器是决策树。可以直接调用。
五、Boosting
Boosting的思想是一种迭代的方法,它每次训练使用的都是同一个训练集。但是每次它会给这些分类错误的样例增加更大的权重,下一次迭代的目标就是能够更容易辨别出上一轮分类错误的样例。最终将这些弱分类器进行加权相加。
注意:Boosting下一次的迭代必须在上一次的基础上。
同样地,基于Boosting思想的有AdaBoost、GBDT等,也可以直接调用。
六、Stacking
stacking是一种分层模型集成框架。以两层为例,第一层由多个基学习器组成,其输入为原始训练集,第二层的模型则是以第一层基学习器的输出作为训练集进行再训练,从而得到完整的stacking模型。
stacking两层模型都使用了全部的训练数据。
第一层模型:
首先数据有训练集和测试集两部分
1.对训练集进行五折交叉验证,把训练集划分为A,B两部分
2.对A部分进行训练,对B部分进行预测,得到a1,五折后则为a1,a2,a3,a4,a5,对他们合并,形成n行一列的数据
3.对测试集进行预测,会得到b1,b2,b3,b4,b5,将各部分相加取平均得到m行一列的数据
4,。以上是一个模型,如果有三个模型,则可以得到A1,A2,A3,B1,B2,B3
5.在此之后,我们把A1,A2,A3并列合并得到一个n行三列的矩阵作为training data,B1,B2,B3并列合并得到一个m行三列的矩阵作为testing data。让下一层的模型,基于他们进一步训练。
#创建训练的数据集 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] #对于测试集,直接用这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() 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("val auc Score: %f" % (roc_auc_score(y_predict, y_submission)))
备注:此处只是一部分代码
七、Blending
Bending是一种模型融合方法,对于一般的Blending,主要思路是把原始的训练集先分成两部分,比如70%的数据作为新的训练集,剩下30%的数据作为测试集。第一层我们在这70%的数据上训练多个模型,然后去预测那30%数据的label。在第二层里,我们就直接用这30%数据在第一层预测的结果做为新特征继续训练即可。
#创建训练的数据集 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) #5折stacking n_folds = 5 skf = list(StratifiedKFold(y, n_folds)) #切分训练数据集为d1,d2两部分 X_d1, X_d2, y_d1, y_d2 = train_test_split(X, y, test_size=0.5, random_state=2017) 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("Linear stretch of predictions to [0,1]") y_submission = (y_submission - y_submission.min()) / (y_submission.max() - y_submission.min()) print("val auc Score: %f" % (roc_auc_score(y_predict, y_submission)))
总结:
以上的七种模型融合方法,在一定情况下可以提高模型的准确率,方法没有好坏之分,各有自己的优缺点,具体实施可针对具体场景。