集成学习-13
1. Stacking模型
针对上一章节Blending对数据集的处理的方法,我们知道:Blending在集成的过程中只会用到验证集的数据,对数据实际上是一个很大的浪费。为了解决这个问题,我们详细分析下Blending到底哪里出现问题并如何改进。在Blending中,我们产生验证集的方式是使用分割的方式,产生一组训练集和一组验证集,这让我们联想到交叉验证的方式。顺着这个思路,我们对Stacking进行建模(如下图)
stacking 的框架结构与运行过程:
1.选择基模型。我们可以有 xgboost,lightGMB,RandomForest,SVM,ANN,KNN, LR 等等你能想到的各种基本算法模型。
from sklearn import datasets
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
from sklearn.model_selection import cross_val_score
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 StackingCVClassifier
RANDOM_SEED = 42
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=RANDOM_SEED)
clf3 = GaussianNB()
lr = LogisticRegression()
2.将所有数据集生成测试集和训练集(假如训练集为10000,测试集为2500行),之后把训练集分为不交叉的五份。那么上层会进行5折交叉检验,使用训练集中的8000条作为训练集,剩余2000行作为验证集(橙色)。
3.每次验证相当于使用了蓝色的8000条数据训练出一个模型,使用模型对验证集进行验证得到2000条数据,并对测试集进行预测,得到2500条数据,这样经过5次交叉检验,可以得到中间的橙色的5*2000条验证集的结果(相当于每条数据的预测结果),5 *2500条测试集的预测结果。
# Starting from v0.16.0, StackingCVRegressor supports
# `random_state` to get deterministic result.
sclf = StackingCVClassifier(classifiers=[clf1, clf2, clf3], # 第一层分类器
meta_classifier=lr, # 第二层分类器
random_state=RANDOM_SEED)
print('3-fold cross validation:\n')
4.接下来会将验证集的5 2000条预测结果拼接成10000行长的矩阵,标记为 A1 ,而对于5 2500行的测试集的预测结果进行加权平均,得到一个2500一列的矩阵,标记为 B1 。
上面得到一个基模型在数据集上的预测结果 A1 、 B1 ,这样当我们对3个基模型进行集成的话,相于得到了 A1 、 A2 、 A3 、 B1 、 B2 、 B3 六个矩阵。
5.之后我们会将 A1 、 A2 、 A3 并列在一起成10000行3列的矩阵作为training data, B1 、 B2 、 B3 合并在一起成2500行3列的矩阵作为testing data,让下层学习器基于这样的数据进行再训练。
for clf, label in zip([clf1, clf2, clf3, sclf], ['KNN', 'Random Forest', 'Naive Bayes','StackingClassifier']):
scores = cross_val_score(clf, X, y, cv=3, scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
6.再训练是基于每个基础模型的预测结果作为特征(三个特征),次学习器会学习训练如果往这样的基学习的预测结果上赋予权重w,来使得最后的预测最为准确
# 我们画出决策边界
from mlxtend.plotting import plot_decision_regions
import matplotlib.gridspec as gridspec
import itertools
gs = gridspec.GridSpec(2, 2)
fig = plt.figure(figsize=(10,8))
for clf, lab, grd in zip([clf1, clf2, clf3, sclf],
['KNN',
'Random Forest',
'Naive Bayes',
'StackingCVClassifier'],
itertools.product([0, 1], repeat=2)):
clf.fit(X, y)
ax = plt.subplot(gs[grd[0], grd[1]])
fig = plot_decision_regions(X=X, y=y, clf=clf)
plt.title(lab)
plt.show()
使用stacking 的一些注意事项
- stacking 的框架设计比较复杂,对于一个基模型要训练 5 次,如果你的一个 xgb 模型要训练 2 个小时,即使在进行 stacking 的时候每折减少了五分之一的数据量,你的计算时间仍然是很可观的,加起来应该还是 8-9 小时,所以耗费时间很长(想像一下一个 stacking 框架跑一个基模型要大半天,简直太可怕)。所以建议大家在使用的时候要计算时间的耗费,或者可以改为 3 折,4 折等等;
- 基模型除了是不同参数的相同模型之外,比如不同参数的 xgboost,或者不同 K 值的 KNN 等等;更重要的是要尽可能的多加一些不同种类的基模型进去,也就是说所谓的模型要“跨越空间” 的概念。这样的话我们的集成结果会更加稳健,更加精确。
参考 :