1 为什么要做模型融合
模型融合希望起到的作用是:一种类似于“三个臭皮匠,顶一个诸葛亮”的效果。
认为每个模型可能都只能学到一份数据一方面的特征,因此希望结合不同的模型学到的结果,综合起来来对未知的数据进行预测!实现更好的泛化性!
2 模型融合方法
多模型做完之后,希望能融合多模型结果。大概有三种方法:
- 分类问题:Voting
- 回归问题:Averaging
- Stacking方法。每一次的结果标签是下一次的输入!无论回归还是分类都ok!
前两种都比较好理解,就是最后一种Stacking 有一点复杂!
另外两个机器学习的模型框架应该也算的:不论回归和分类都可以进行!
- bagging
- boosting
关于bagging和boosting的具体介绍可以见之前的博客:机器学习 | 集成学习
2.1 Voting
直译过来就是投票的意思,而实际做的时候也就是投票进行!
假设对于一个二分类问题,有3个基础模型,那么就采取投票制的方法,投票多者确定为最终的分类。比如分别预测结果为1 1 0 则这个样本类别为1!少数服从多数!
同时Voting分为两种:硬分类和软分类!
2.1.1 硬分类
原理:直接根据类别结果来判断!见下图:
代码:
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
clf1 = LogisticRegression(solver='lbfgs', multi_class='multinomial',
random_state=1)
clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
clf3 = GaussianNB()
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
y = np.array([1, 1, 1, 2, 2, 2])
eclf1 = VotingClassifier(estimators=[
('lr', clf1), ('rf', clf2), ('gnb', clf3)], voting='hard')
eclf1 = eclf1.fit(X, y)
注意:有时候Voting反而还不如某一个精度较高的单模型效果好!这个看具体数据而言!
2.1.2 软分类
原理:见下图,把概率当做权值,根据概率来考虑:
代码:
from sklearn.linear_model import LogisticRegression
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier, VotingClassifier
clf1 = LogisticRegression(solver='lbfgs', multi_class='multinomial',
random_state=1)
clf2 = RandomForestClassifier(n_estimators=50, random_state=1)
clf3 = GaussianNB()
X = np.array([[-1, -1], [-2, -1], [-3, -2], [1, 1], [2, 1], [3, 2]])
y = np.array([1, 1, 1, 2, 2, 2])
eclf1 = VotingClassifier(estimators=[
('lr', clf1), ('rf', clf2), ('gnb', clf3)], voting='soft')
eclf1 = eclf1.fit(X, y)
2.2 Averaging
更多用在回归问题,但分类问题也可以去做,就是平均预测的概率,和Voting中的软分类含义一致!
而这个模型权重就是自己一开始可以设置的。
2.3 Stacking
Stacking应该是这里面最难理解的一个了!当时小编也查了很多的资料,下面和大家分享一下!
首先上一个特别好的图:
我们来尝试解释下上面的图:
- 先将数据分为训练集train和测试集test
- 然后对训练集进行5折交叉验证,比如train1,就是结合train2~5的数据训练模型,然后来预测train1得到预测结果!也就是灰色的部分!那大家就会问一个问题,也是小编当时纠结很久的,这个灰色的部分到底是什么?是预测结果的标签或概率还是train1的特征+标签,后来看了一个知乎大v说实际的时候两者都可以尝试,然后看哪个效果好!这里不妨就认为是仅仅把标签(即预测结果)放进来了!
- 在第二步的时候,对每一折进行了预测的同时,也对一开始分的test进行预测!得到预测结果!目的是为了得到下一步新的数据的时候的新测试集!把5折各自训练的模型在测试集上的预测结果进行一个平均就得到了浅蓝色的完整的测试集的预测结果!
- 对于不同的模型,重复上述两步过程!
- 拼接模型预测的结果! 将不同模型的训练集每一折上预测的结果的标签作为一列新的特征,比如这里是XGB和LR两列新特征!同时把训练集一开始对应的实际的Label作为新的训练集的y,测试集呢?将一开始分的测试集的预测结果为测试集的特征,这里还是XGB和LR两列新特征,并且把一开始测试集对应的真实的Label作为新的测试集的Label!这样崭新的训练集和测试集就出来了!实现了拼接!接下来再对这个数据集进行训练预测!
所以将不同的模型用在Stacking中其实是增加了新的训练集和测试集的特征维度!真实的y标签还是不发生变化的!
代码的实现:使用mlxtend库
from sklearn import datasets
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
from sklearn import model_selection
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
import numpy as np
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
meta_classifier=lr)
print('3-fold cross validation:\n')
for clf, label in zip([clf1, clf2, clf3, sclf],
['KNN',
'Random Forest',
'Naive Bayes',
'StackingClassifier']):
scores = model_selection.cross_val_score(clf, X, y,
cv=3, scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]"
% (scores.mean(), scores.std(), label))
参考资料
- Stacking代码实现:https://blog.csdn.net/willduan1/article/details/73618677
- https://zhuanlan.zhihu.com/p/25836678
- Stacking解释的通俗易懂:https://blog.csdn.net/qq_18916311/article/details/78557722
- Voting讲的比较好:https://blog.csdn.net/m0_37725003/article/details/81095555
- Voting官方文档:https://scikit-learn.org/stable/modules/generated/sklearn.ensemble.VotingClassifier.html
- averaging : https://blog.csdn.net/shine19930820/article/details/75209021#commentBox