在前面介绍两种集成学习算法后,下面将引入一种新的集成思想。当数据很多时,Stacking学习法变应运而生。将单个的学习器称之为初级学习器,用以结合的学习器称之为元学习器。
上一篇,Bagging,点我
上一篇,Boosting,点我
Stacking
Stacking总体思想:
前面的Bagging算法中我们通过训练多个弱学习器,最终通过软/硬投票等方式作出最终的预测结果。那么我们是否可以使用同一份大的数据集,划分为多份,训练处多个弱学习器。然后最终我们采用一个模型(元学习器)来代替最后的预测环节(相当于用一个学习器代替软/硬投票这个过程)
Stacking算法流程:
1:首先将实例样本相似的分为m份,m对应着学习器层数
2:使用第i份数据训练第i层初级学习器,共有m-1层初级学习器,第m层对应着元学习器用以最后的输出
3:用最后一份数据作为训练后模型的输入,后一层初级学习器的输入将变为前面一层初级学习器的输出。
4:每层依次类推
5:将m-1层输出作为第m层的输入,最终的元学习器将相当于前面的投票系统一样,作出最终的预测。
Stacking算法:
如下面这幅图所示,我们将数据划分为三份,分别用1,2份数据训练1,2层初级学习器。第三份数据作为整体输出,
样本中每个实例将会有三种不同的输出结果,这样就由原来的一维变为了三个初级学习器输出结果的叠加,变为了三维。
这样就在经过第一层初级学习器后形成了一个新的三维数据集,然后这个新的数据集作为第二层初级学习器的输入,由
第二层初级学习器做出预测,最终通过第三层的初级学习器作出最终的输出
Stacking实例
很不幸,在sklearn中不支持Stacking算法,但是根据其思想我们能够做一个最简单的Stacking模型
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
from sklearn.neighbors import KNeighborsClassifier
import matplotlib.pyplot as plt
import numpy as np
# 获取数据,查看数据集大小。还是我们老朋友鸢尾花
dataset = load_iris()
dataset.target.shape
features = dataset.data
target = dataset.target
# 分割数据,这里最简单起见我们采用两层结构,一层初级学习器,一层元学习器
x_train,x_test,y_train,y_test = train_test_split(features,target,test_size=0.5,random_state=123)
# 训练初级学习器
estimator1 = DecisionTreeClassifier(criterion="gini",max_depth=6,max_features=4,random_state=1)
estimator2 = SVC(C=0.8,kernel="rbf",degree=3,probability=True,random_state=2)
estimator3 = KNeighborsClassifier(n_neighbors=5,algorithm="ball_tree",p=2)
estimator_list = [estimator1,estimator2,estimator3]
for estimator in estimator_list:
estimator.fit(x_train,y_train)
# 利用初级学习器预测测试集
val_dict=dict()
for index,estimator in enumerate(estimator_list):
y_pred= estimator.predict(x_test)
val_dict[index]=y_pred
# 将三个初级学习器输出整合成一个新的高维的样本特征
new_features = np.stack((val_dict[0],val_dict[1],val_dict[2]),axis=1)
# 元学习器,这里我们采取取众数作为元学习器,可以设计更为复杂的元学习器
from scipy import stats
# 取众数,两种方法,方法一利用scipy种的stats模块中mode方法直接求取众数
# 方法二利用numpy中discount先统计样本中非负整型个数,再用argmax()求取众数
y_pred = list()
for line in range(new_features.shape[0]):
# num = stats.mode(new_features[line])
# mode = num.mode
num = np.bincount(new_features[line])
mode = np.argmax(num)
y_pred.append(mode)
# 评估metrics
y_pred = np.array(y_pred)
n=0
for i ,j in zip(y_pred,y_test):
if i!=j:
n+=1
score = (y_test.shape[0]-n)/y_test.shape[0]