1. 初识stacking
本章我们继续讨论集成学习方法的最后一个成员–Stacking。Stacking严格来说并不是一种算法,而是精美而又复杂的,对模型集成的一种策略。Stacking集成算法可以理解为一个两层的集成,第一层含有多个基础分类器,把预测的结果(元特征)提供给第二层, 而第二层的分类器通常是逻辑回归,他把一层分类器的结果当做特征做拟合输出预测结果。在介绍Stacking之前,我们先来对简化版的Stacking进行讨论,也叫做Blending.
2. Blending模型
Blending是一种模型融合的方式,第一层通过将训练集出一部分作为holdout set,然后通过剩下的数据生成模型对holdout set (留出法交叉验证 )进行预测,第二层,直接对预测结果建模生成第二层的模型,如图所示。Blending是 Netflix获胜者提出来的模型融合方法,更偏向工程类,因此本文不会有太多的公式。
(1) 将原始数据划分成三部分:将数据划分为训练集和测试集(test_set),其中训练集需要再次划分为训练集(train_set)和验证集(val_set);具体如图所示。进一步的说明总的数据集被分成训练集和测试集,如80%训练集和20%测试集,然后在这80%的训练集中再拆分训练集70%和验证集30%,因此拆分后的数据集由三部分组成:训练集80% *70% 、测试集20%、验证集80% *30% 。训练集是为了训练模型,测试集是为了调整模型(调参),验证集则是为了检验模型的优度。
# 加载相关工具包
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
import seaborn as sns
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target
features = iris.feature_names
iris_data = pd.DataFrame(X,columns=features)
iris_data['target'] = y
# print("target", np.unique(iris["target"]))
iris = iris_data[iris_data['target']!= 2]
X = iris[['sepal length (cm)','sepal width (cm)']].values
y = iris['target'].values
(2) 创建第一层的多个模型,这些模型可以使同质的也可以是异质的;
(3) 使用train_set训练步骤2中的多个模型,然后用训练好的模型预测val_set和test_set得到val_predict, test_predict1;
在(2)-(3)步中,我们使用训练集创建了K个模型,如SVM、random forests、XGBoost等,这个是第一层的模型。 训练好模型后将验证集输入模型进行预测,得到K组不同的输出,我们记作
A
1
,
.
.
.
,
A
K
A_1,...,A_K
A1,...,AK,然后将测试集输入K个模型也得到K组输出,我们记作
B
1
,
.
.
.
,
B
K
B_1,...,B_K
B1,...,BK ,其中
A
i
A_i
Ai 的样本数与验证集一致,
B
i
B_i
Bi 的样本数与测试集一致。如果总的样本数有10000个样本,那么使用5600个样本训练了K个模型,输入验证集2400个样本得到K组2400个样本的结果
A
1
,
.
.
.
,
A
K
A_1,...,A_K
A1,...,AK,输入测试集2000个得到K组2000个样本的结果
B
1
,
.
.
.
,
B
K
B_1,...,B_K
B1,...,BK
# 设置第一层分类器
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
clfs = [SVC(probability = True),RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'),KNeighborsClassifier()]
val_features = np.zeros((X_val.shape[0], len(clfs)))
test_features = np.zeros((X_test.shape[0], len(clfs)))
for i, clf in enumerate(clfs):
clf.fit(X_train, y_train)
#预测概率值
val_predict = clf.predict_proba(X_val)[:, 1]
val_features[:,i] = val_predict
test_predict = clf.predict_proba(X_test)[:, 1]
test_features[:, i] = test_predict
(4) 创建第二层的模型,使用val_predict作为训练集训练第二层的模型;
# 设置第二层分类器
from sklearn.linear_model import LogisticRegression
lr = LogisticRegression()
# 将第一层的验证集的结果输入第二层训练第二层分类器
lr.fit(val_features,y_val)
# 输出预测的结果
from sklearn.model_selection import cross_val_score
cross_val_score(lr,test_features,y_test,cv=5)
(5) 使用第二层训练好的模型对第二层测试集test_predict1进行预测,该结果为整个测试集的结果
3. 总结与分析
1.简单(因为不用进行k次的交叉验证来获得stacker feature)
2.避开了一个信息泄露问题:generlizers和stacker使用了不一样的数据集
3.在团队建模过程中,不需要给队友分享自己的随机种子
缺点在于: 1.使用了很少的数据(是划分hold-out作为测试集,并非cv),对数据实际上是一个很大的浪费。
参考: