参考链接:https://blog.csdn.net/willduan1/article/details/73618677
stacking
Stacking先从初始数据集训练出初级学习器,将初级学习器的输出当作特征构成新数据集,利用新数据集再训练次级学习器(meta-learner)。初级学习器通常使用不同的学习算法。
训练阶段,若直接用初级学习器的训练集来产生次级训练集,过拟合风险过大,因此一般使用交叉验证的方式,用初级学习器未使用的样本来产生次级学习器的训练器。以k折交叉验证为例,对某一个算法使用交叉验证,将k个作为验证集的部分的输出组合起来作为次级训练集的特征。过程如下:
次级学习器的输入属性表示和次级学习算法对Stacking集成的泛化性能有很大影响。有研究表明,将初级学习器的输出类概率作为次级学习器的输入特征,用多响应线性回归(Multi-response Linear Regression)作为次级学习算法效果较好。
使用mlxtend实现stacking
参考链接:http://rasbt.github.io/mlxtend/
mlxtend帮助文档:https://sebastianraschka.com/pdf/software/mlxtend-latest.pdf
mlxtend是一个机器学习库,里面包含了一些机器学习的包和可视化函数等等,其中包括了sklearn中没有的stacking操作。文档从88页开始讲的stacking相关的部分。
通过stacking产生的特征可以分为多种形式:
(以下例子来自官方文档),下面的例子全部为不带交叉验证时初始学习器学习到的特征,如果使用交叉验证,可以将StackingClassifier
都变为StackingCVClassifier
即可。
(1)将初级分类器产生的类别标签作为新特征
使用KNN,朴素贝叶斯,随机森林作为初级分类器,LR作为次级分类器。
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
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))
输出:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.91 (+/- 0.06) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.95 (+/- 0.03) [StackingClassifier]
可视化代码:
import matplotlib.pyplot as plt
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',
'StackingClassifier'],
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()
(2)将初级分类器产生的输出类概率作为新特征
对于输出概率,有两种不同的处理方式。假设有2个初级分类器和3个类别输出概率:
如果average_probas=True
,则对分类器的结果求平均,得到:
如果average_probas=False
,则分类器的所有结果都保留作为新的特征,这种方法是推荐的方法
sclf = StackingClassifier(classifiers=[clf1, clf2, clf3],
use_probas=True,
average_probas=False,
meta_classifier=lr)
输出:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.91 (+/- 0.06) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.94 (+/- 0.03) [StackingClassifier]
(3)初级分类器采用不同的训练集子集来训练
需要结合sklearn中的pipeline和ColumnSelector来实现
from sklearn.datasets import load_iris
from mlxtend.classifier import StackingClassifier
from mlxtend.feature_selection import ColumnSelector
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
iris = load_iris()
X = iris.data # (150,4)
y = iris.target
pipe1 = make_pipeline(ColumnSelector(cols=(0, 2)), # 选择第0,2列特征
LogisticRegression())
pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)), # 选择第1,2,3列特征
LogisticRegression())
sclf = StackingClassifier(classifiers=[pipe1, pipe2],
meta_classifier=LogisticRegression())
sclf.fit(X, y)