模型融合通常可以在各种不同的机器学习任务中使结果获得提升,单个模型效果总会不尽如人意,但是通过模型融合能结合各个模型的有点,从而提高模型的效果。
Voting即投票机制,分为软投票和硬投票两种,其原理采用少数服从多数的思想。
硬投票:对多个模型直接进行投票,最终投票数最多的类为最终被预测的类。
软投票:和硬投票原理相同,增加了设置权重的功能,可以为不同模型设置不同权重,进而区别模型不同的重要度。
Averaging,其原理是对模型结果取平均。
处理回归问题,直接取平均值作为最终的预测值。(也可以使用加权平均)
平均法存在问题就是如果不同回归方法的预测结果波动幅度相差比较大,那么波动小的回归结果在融合时候起的作用就比较小
Ranking的思想和Averaging一致,但是因为上述平均法存在一定的问题。
所以这里采用了把排名做平均,如果有权重,则求n个模型权重比排名之和,即为最后的结果
Bagging方法的出现,可以完美地解决了决策树过拟合的问题,同时bagging的使用也会使分类器分类效果得到了显著的提高。
应用场景:对不稳定的分类器做Bagging是一个好主意。在机器学习中,如果训练数据的一个小变化导致学习中的分类器的大变化,则该算法(或学习算法)被认为是不稳定的。
Bagging就是采用有放回的方式进行抽样,用抽样的样本建立子模型,对子模型进行训练,这个过程重复多次,最后进行融合。大概分为两步:
1.重复K次
有放回地重复抽样建模
训练子模型
2.模型融合
模型融合,如果是分类问题用voting解决 。如果是回归问题用average解决。
注意:在bagging集成中,各个模型的预测不会彼此依赖。Bagging算法不用我们自己实现,随机森林就是基于Bagging算法的一个典型例子,采用的基分类器是决策树。可以直接调用。
Boosting的思想是一种迭代的方法,它每次训练使用的都是同一个训练集。但是每次它会给这些分类错误的样例增加更大的权重,下一次迭代的目标就是能够更容易辨别出上一轮分类错误的样例。最终将这些弱分类器进行加权相加。
注意:Boosting下一次的迭代必须在上一次的基础上。
同样地,基于Boosting思想的有AdaBoost、GBDT等,也可以直接调用。
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。让下一层的模型,基于他们进一步训练。
附上代码:
#!pip install mlxtend
import warnings
warnings.filterwarnings('ignore')
import itertools
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingClassifier
from sklearn.model_selection import cross_val_score, train_test_split
from mlxtend.plotting import plot_learning_curves
from mlxtend.plotting import plot_decision_regions
# 以python自带的鸢尾花数据集为例
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
meta_classifier=lr)
label = ['KNN', 'Random Forest', 'Naive Bayes', 'Stacking Classifier']
clf_list = [clf1, clf2, clf3, sclf]
fig = plt.figure(figsize=(10,8))
gs = gridspec.GridSpec(2, 2)
grid = itertools.product([0,1],repeat=2)
clf_cv_mean = []
clf_cv_std = []
for clf, label, grd in zip(clf_list, label, grid):
scores = cross_val_score(clf, X, y, cv=3, scoring='accuracy')
print("Accuracy: %.2f (+/- %.2f) [%s]" %(scores.mean(), scores.std(), label))
clf_cv_mean.append(scores.mean())
clf_cv_std.append(scores.std())
clf.fit(X, y)
ax = plt.subplot(gs[grd[0], grd[1]])
fig = plot_decision_regions(X=X, y=y, clf=clf)
plt.title(label)
plt.show()
Bending是一种模型融合方法,对于一般的Blending,主要思路是把原始的训练集先分成两部分,比如70%的数据作为新的训练集,剩下30%的数据作为测试集。第一层我们在这70%的数据上训练多个模型,然后去预测那30%数据的label。在第二层里,我们就直接用这30%数据在第一层预测的结果做为新特征继续训练即可。
Blending的优点在于:
1.比stacking简单(因为不用进行k次的交叉验证来获得stacker feature)
2.避开了一个信息泄露问题:generlizers和stacker使用了不一样的数据集
而缺点在于:
1.使用了很少的数据(第二阶段的blender只使用training set10%的量)
2.blender可能会过拟合
3.stacking使用多次的交叉验证会比较稳健
对于实践中的结果而言,stacking和blending的效果是差不多的,所以使用哪种方法都没什么所谓,完全取决于个人爱好。
代码实例:
def blend(train,test,target):
'''5折'''
# n_flods = 5
# skf = list(StratifiedKFold(y, n_folds=n_flods))
'''切分训练数据集为d1,d2两部分'''
X_d1, X_d2, y_d1, y_d2 = train_test_split(train, target, test_size=0.5, random_state=914)
train_ = np.zeros((X_d2.shape[0],len(clfs*3)))
test_ = np.zeros((test.shape[0],len(clfs*3)))
for j,clf in enumerate(clfs):
'''依次训练各个单模型'''
# print(j, clf)
'''使用第1个部分作为预测,第2部分来训练模型,获得其预测的输出作为第2部分的新特征。'''
# X_train, y_train, X_test, y_test = X[train], y[train], X[test], y[test]
X_d1fillna=X_d1.fillna(0)
X_d2fillna = X_d2.fillna(0)
X_predictfillna= test.fillna(0)
clf.fit(X_d1fillna,y_d1)
y_submission = clf.predict(X_d2fillna)
y_test_submission = clf.predict(X_predictfillna)
train_[:,j*3] = y_submission*y_submission
'''对于测试集,直接用这k个模型的预测值作为新的特征。'''
test_[:, j*3] = y_test_submission*y_test_submission
train_[:, j+1] =(y_submission - y_submission.min()) /(y_submission.max() - y_submission.min())
'''对于测试集,直接用这k个模型的预测值作为新的特征。'''
y_test_submission = (y_test_submission - y_test_submission.min()) / \
(y_test_submission.max() - y_test_submission.min())
test_[:, j+1] = y_test_submission
train_[:, j+2] = np.log(y_submission)
'''对于测试集,直接用这k个模型的预测值作为新的特征。'''
y_test_submission =np.log(y_test_submission)
test_[:, j+2] = y_test_submission
# print("val auc Score: %f" % r2_score(y_predict, dataset_d2[:, j]))
print('已完成第',j)
train_.to_csv('./input/train_blending.csv', index=False)
test_.to_csv('./input/test_blending.csv', index=False)
总结:
以上的七种模型融合方法,在一定情况下可以提高模型的准确率,方法没有好坏之分,各有自己的优缺点,具体实施可针对具体场景。