"> "> 机器学习-集成学习 | Yufei Luo's Blog

机器学习-集成学习

概述

集成学习(Ensemble Learning)指的是通过构建并结合多个学习器来完成学习任务,它的一般方法是先产生一组个体学习器,然后再使用某种策略将它们结合起来。而个体学习器通常是由一个现有的学习算法(如神经网络、决策树、线性回归等等)从训练数据中产生。通过将多个学习器按照某种方式进行结合,往往可以获得比单一学习器更加优越的泛化性能,这一特点对于弱学习器(指的是泛化性能略优于随机猜测的学习器)尤其明显。

根据个体学习器的生成方式不同,可以将集成学习方法大致分为两大类:

  1. 序列化方法:个体学习器之间存在强依赖关系,必须按照序列串行生成,其代表为Boosting;
  2. 并行化方法:个体学习器之间不存在依赖关系,可以同时生成,其代表为Bagging

下面我们分别对Boosting和Bagging这两种方法进行介绍。

Boosting

基本思想

Boosting是一族可以将弱学习器提升为强学习器的算法,这一族算法的工作机制为:先从初始训练集中训练出一个基学习器,然后根据基学习器的表现对训练样本分布进行调整,使得先前基学习器预测错误的训练样本在后续会受到更多关注,然后基于调整后的样本分布来训练下一个基学习器;如此重复进行,直到基学习器数目达到事先指定的值,最终将所有的基学习器进行加权结合即可。

从偏差-方差分解的角度来看,Boosting主要关注降低偏差。因此Boosting可以基于泛化性能弱的学习器构建出很强的集成模型。

Boosting族的算法有很多,常用的包括AdaBoost、GBDT、XGBoost、LightGBM等。在下文中我们着重介绍Adaboost的原理;而后面这些为基于树模型的提升算法,将会用另外一篇文章单独介绍。

AdaBoost

算法描述

给定一个训练数据集\(D=\{(\boldsymbol{x}_1,y_1),(\boldsymbol{x}_2,y_2),\dots, (\boldsymbol{x}_N,y_N)\}\),其中\(\boldsymbol{x}_i \in R^n\)\(y_i \in \{-1,1\}\)\(i=1,2,\dots,N\)。AdaBoost算法使用\(M\)个基本分类器\(G_m(\boldsymbol{x}):R^n\rightarrow \{-1,1\},m=1,2,\dots,M\),生成强分类器\(G(\boldsymbol{x})\)的步骤如下:

  1. 初始化训练数据的权值分布: \[ W_1=(w_{11},w_{12},\dots,w_{1N}),~w_{1i}=\frac{1}{N},~i=1,2,\dots,N \]

  2. \(m=1,2,\dots,M\),做如下操作:

    1. 使用权值分布\(W_m\)的训练数据集学习得到基本分类器\(G_m(\boldsymbol{x})\)

    2. 计算\(G_m(\boldsymbol{x})\)在训练数据集上的分类误差率\(e_m=P[G_m(\boldsymbol{x}_i\ne y_i)]=\sum_{i=1}^{N}w_{mi}I[G_m(\boldsymbol{x}_i\ne y_i)]\)

    3. 计算分类器\(G_m(\boldsymbol{x})\)的系数\(\alpha_m=\frac{1}{2}\ln\frac{1-e_m}{e_m}\)。也就是说,当误差率小于50%的时候\(\alpha_m\)为正数,且误差率越低则\(\alpha_m\)的值越大,相当于越相信模型\(G_m(\boldsymbol{x})\)的分类结果;否则\(\alpha_m\)为负数,相当于是我们不相信模型的预测结果,此时取模型预测的相反结果反而准确率更高。但是一般情况下,我们假设\(\alpha_m>0\)

    4. 更新训练数据集的权值分布: \[ W_{m+1}=(w_{m+1,1},w_{m+1,2},\dots,w_{m+1,N}) \\ w_{m+1,i}=\frac{w_{mi}}{Z_m}\exp(-\alpha_m y_i G_m(\boldsymbol{x}_i)),~i=1,2,\dots,N \] 其中\(Z_m=\sum_{i=1}^{N}w_{mi}\exp (-\alpha_m y_i G_m(\boldsymbol{x}_i))\)为规范化因子,它使得\(\sum_{i=1}^{N}w_{m+1,i}=1\)

      在这一步中,如果\(\alpha_m y_i G_m(\boldsymbol{x}_i)\)的值为正数,说明模型预测的结果正确,这也一定程度上意味着这一样本比较容易分类,因此在接下来的训练过程中不需要很关注这一样本,因此将其权重缩小;反之则说明这一样本不太容易被正确分类,因此在接下来的学习中需要特别关注,因此增大其权重。

  3. 构建基本分类器的线性组合: \[ f(\boldsymbol{x})=\sum_{m=1}^{M}\alpha_m G_m(\boldsymbol{x}) \] 最终分类器\(G(\boldsymbol{x})\)为基本分类器的线性组合: \[ G(\boldsymbol{x})=\text{sign}(f(\boldsymbol{x}))=\text{sign} \left( \sum_{m=1}^{M}\alpha_m G_m(\boldsymbol{x}) \right) \] 这相当于最终预测结果是\(M\)个基本分类器的加权表决结果,其中分类越准确的基本学习器对应的系数\(\alpha_m\)的值越大,也就是其预测结果对于最终的表决结果也影响更大。

算法解释

AdaBoost算法可以认为是模型为加法模型、损失函数为指数函数、学习算法为前向分布算法时的二类分类学习方法。

考虑加法模型\(f(\boldsymbol{x})=\sum_{m=1}^{M}\beta_m b(\boldsymbol{x};\gamma_m)\),其中\(b(\boldsymbol{x};\gamma_m)\)为基函数,\(\gamma_m\)为基函数的参数,\(\beta_m\)为基函数的系数。在给定训练数据以及损失函数\(L(y,f(\boldsymbol{x}))\)的条件下,学习加法模型\(f(\boldsymbol{x})\)就变为求解如下的损失函数极小化问题: \[ \min_{\beta_m,\gamma_m} \sum_{i=1}^{N}L\left( y_i,\sum_{m=1}^{M}\beta_m b(\boldsymbol{x}_i;\gamma_m) \right) \] 前向分布算法的求解思路是,考虑到学习的模型为加法模型,如果可以使用从前向后的求解方式,每一步只学习一个基函数及其系数,逐步逼近上述的优化目标函数,这样便可以降低优化的复杂度。也就是说,每一步只需要优化如下的表达式: \[ \min_{\beta,\gamma} \sum_{i=1}^{N}L\left( y_i,f_{m-1}(\boldsymbol{x}_i)+\beta b(\boldsymbol{x}_i;\gamma) \right) \] 对于AdaBoost算法来说,它可以看作是由基本分类器组成的加法模型。它的基函数相当于是基本分类器,前向分布算法相当于是在每一步学习基本分类器的函数表达式以及其对应的系数。下面证明它的损失函数是指数损失函数\(L(y,f(\boldsymbol{x}))=\exp(-yf(\boldsymbol{x}))\)时,前向学习算法的学习过程等价于AdaBoost算法的学习过程:

我们假设经过\(m-1\)轮迭代,前向分布算法得到了\(f_{m-1}(\boldsymbol{x})=\alpha_1 G_1(\boldsymbol{x})+\alpha_2 G_2(\boldsymbol{x})+\dots+\alpha_{m-1} G_{m-1}(\boldsymbol{x})\),在第\(m\)轮迭代得到\(\alpha_m,G_m(\boldsymbol{x})\)以及\(f_{m}(\boldsymbol{x})=f_{m-1}(\boldsymbol{x})+\alpha_m G_m(\boldsymbol{x})\)。目标是使得前向分布算法得到的\(\alpha_m,G_m(\boldsymbol{x})\)能够使得\(f_{m}(\boldsymbol{x})\)在训练数据集\(D\)上的指数损失最小,即: \[ \alpha_m,G_m(\boldsymbol{x})=\text{arg}\min_{\alpha,G}\sum_{i=1}^{N}\exp [-y_i (f_{m-1}(\boldsymbol{x}_i)+\alpha G(\boldsymbol{x}_i))] \] 上式可以改写为: \[ \alpha_m,G_m(\boldsymbol{x})=\text{arg}\min_{\alpha,G} \sum_{i=1}^{N}\bar{w}_{mi}\exp [-y_i \alpha G(\boldsymbol{x}_i)] \] 其中\(\bar{w}_{mi}=\exp[-y_if_{m-1}(\boldsymbol{x}_i)]\)\(\bar{w}_{mi}\)不依赖于\(\alpha\)\(G(\boldsymbol{x})\),因此与最小化无关,但是它与前\(m-1\)轮的迭代结果有关,随着每一轮迭代而发生改变。

接下来我们证明使得损失函数达到最小的\(\alpha_m^*\)\(G_m^*(\boldsymbol{x})\)与AdaBoost算法得到的结果相同。

首先我们求解\(G_m^*(\boldsymbol{x})\)。假设\(\alpha>0\),使得表达式取值最小的\(G(\boldsymbol{x})\)是通过最小化如下表达式获得的: \[ G_m^*(\boldsymbol{x})=\text{arg}\min_{G}\sum_{i=1}^{N} \bar{w}_{mi}I(y_i\ne G(\boldsymbol{x}_i)) \] 其中\(\bar{w}_{mi}=\exp [-y_if_{m-1}(\boldsymbol{x}_i)]\)。求解这一表达式所得到的优化器与AdaBoost算法在第\(m\)步迭代时所得到的分类器相同,因为它是使得第\(m\)轮加权训练数据分类误差率最小的基本分类器。

然后我们求解\(\alpha_m^*\)。由于 \[ \begin{aligned} &\sum_{i=1}^{N}\bar{w}_{mi}\exp [-y_i \alpha G(\boldsymbol{x}_i)]\\ =&\sum_{y_i=G(\boldsymbol{x}_i)}\bar{w}_{mi} e^{-\alpha}+\sum_{y_i\ne G(\boldsymbol{x}_i)}\bar{w}_{mi} e^{\alpha} \\ =&(e^{\alpha}-e^{-\alpha})\sum_{i=1}^{N}\bar{w}_{mi}I(y_i\ne G(\boldsymbol{x}_i))+e^{-\alpha}\sum_{i=1}^{N}\bar{w}_{mi} \end{aligned} \] 将已求得的\(G_m^*(\boldsymbol{x})\)代入上式,对\(\alpha\)求导并令导数为0,可得: \[ \alpha_m^*=\frac{1}{2}\log \frac{1-e_m}{e_m} \] 其中\(e_m\)指的是分类误差率: \[ e_m=\frac{\sum_{i=1}^{N}\bar{w}_{mi}I(y_i\ne G_m^*(\boldsymbol{x}_i))}{\sum_{i=1}^{N}\bar{w}_{mi}}=\sum_{i=1}^{N}{w}_{mi}I(y_i\ne G_m^*(\boldsymbol{x}_i)) \] 此处求得的\(\alpha_m^*\)与AdaBoost算法在第\(m\)步迭代时求出的\(\alpha_m\)相等。

最后我们分析样本权值的更新。从\(f_{m}(\boldsymbol{x})=f_{m-1}(\boldsymbol{x})+\alpha_m G_m(\boldsymbol{x})\)以及\(\bar{w}_{mi}=\exp [-y_if_{m-1}(\boldsymbol{x}_i)]\),可得: \[ \bar{w}_{m+1,i}=\bar{w}_{mi}\exp [-y_i\alpha_m G_m(\boldsymbol{x})] \] 从中可以看出,此处求得的样本权重与AdaBoost的样本权重只相差了一个规范化因子,因此它们也是等价的。

训练误差分析

AdaBoost算法最终分类器的训练误差界为: \[ \frac{1}{N}\sum_{i=1}^{N}I(G(\boldsymbol{x}_i)\ne y_i)\le \frac{1}{N} \sum_{i}\exp(-y_i f(\boldsymbol{x}_i))=\prod_m Z_m \] 其中\(G(\boldsymbol{x})\)\(f(\boldsymbol{x})\)\(Z_m\)参考算法描述部分。

对于上面的表达式,我们分两部分证明。对于前半部分,当\(G(\boldsymbol{x}_i)\ne y_i\)时,\(-y_i f(\boldsymbol{x}_i)\ge 0\),因此\(\exp(-y_i f(\boldsymbol{x}_i))\ge 1\);当\(G(\boldsymbol{x}_i)= y_i\)时,\(I(G(\boldsymbol{x}_i)\ne y_i)=0\),而\(\exp(-y_i f(\boldsymbol{x}_i))>0\)一定成立。故前半部分得证。

对于后半部分,推导过程如下: \[ \begin{aligned} \frac{1}{N} \sum_{i}\exp(-y_i f(\boldsymbol{x}_i))=&\frac{1}{N}\sum_{i}\exp \left(-\sum_{m=1}^{M} \alpha_m y_i G_m(\boldsymbol{x}_i) \right) \Leftarrow \left(W_1=(w_{11},w_{12},\dots,w_{1N}),~w_{1i}=\frac{1}{N}\right)\\ =& \sum_{i}w_{1i}\prod_{m=1}^{M} \exp(\alpha_m y_i G_m(\boldsymbol{x}_i)) ~~\Leftarrow \left({Z_m}w_{m+1,i}=w_{mi}\exp(-\alpha_m y_i G_m(\boldsymbol{x}_i))) \right) \\ =& Z_1\sum_{i}w_{2i}\prod_{m=2}^{M} \exp(\alpha_m y_i G_m(\boldsymbol{x}_i)) \\ =& \cdots \\ =&Z_1 Z_2\cdots Z_{m-1}\sum_{i} w_{Mi}\exp(\alpha_M y_i G_M(\boldsymbol{x}_i)) ~~ \Leftarrow \left(Z_m=\sum_{i=1}^{N}w_{mi}\exp (-\alpha_m y_i G_m(\boldsymbol{x}_i)) \right)\\ =&\prod_{m=1}^{M}Z_m \end{aligned} \] 这说明,可以在每一轮选取适当的\(G_m\)使得\(Z_m\)最小,从而使得训练误差下降最快。 对于二分类问题,我们还可以得到如下结果: \[ \prod_{m=1}^{M}Z_m=\prod_{m=1}^{M}[2\sqrt{e_m(1-e_m)}]=\prod_{m=1}^{M}\sqrt{1-4\gamma_m^2}\le \exp\left(-2\sum_{m=1}^M \gamma_m^2\right) \] 其中\(\gamma_m=\frac{1}{2}-e_m\)

对于等式部分,推导过程如下: \[ \begin{aligned} Z_m=&\sum_{i=1}^{N}w_{mi}\exp (-\alpha_m y_i G_m(\boldsymbol{x}_i)) \\ =&\sum_{y_i=G_m(\boldsymbol{x}_i)}{w}_{mi} \exp({-\alpha_m})+\sum_{y_i\ne G_m(\boldsymbol{x}_i)}{w}_{mi} \exp{(\alpha_m)} ~~\Leftarrow \left( e_m=\sum_{i=1}^{N}w_{mi}I[G_m(\boldsymbol{x}_i\ne y_i)] \right)\\ =&(1-e_m)\exp({-\alpha_m})+e_m \exp{(\alpha_m)} ~~\Leftarrow \left( \alpha_m=\frac{1}{2}\ln\frac{1-e_m}{e_m} \right)\\ =&2\sqrt{e_m(1-e_m)} ~~\Leftarrow \left( \gamma_m=\frac{1}{2}-e_m \right)\\ =&\sqrt{1-4\gamma_m^2} \end{aligned} \] 对于不等式部分,通过\(e^x\)\(\sqrt{1-x}\)\(x=0\)处的泰勒展开式可以推导而得。

上式表明,AdaBoost的训练误差是以指数速率下降的。

模型使用

sklearn提供了AdaBoostClassifier分类器和AdaBoostRegressor回归器,用于训练AdaBoost模型。它们的主要参数如下:

  • base_estimator:基学习器的种类
  • n_estimators:最终的Boost模型中含有多少个基学习器,默认值为100
  • learning_rate:学习率
  • loss:模型的损失函数,有线性‘linear’,平方‘square’和指数 ‘exponential’三种选择,默认是线性

Bagging

基本思想

Bagging(Boostrap AGGragatING)的思想是通过采样的方式使得基学习器尽可能具有较大的差异,它的名字来源于自助采样法(Bootstrap Sampling)。给定一个数据集,我们可以通过有放回的随机采样方式可以得到采样集。通过重复采样操作,便可得到多个不同的采样集,然后基于每一个采样集训练出一个基学习器,再将它们进行结合,这便是Bagging的基本流程。在预测结果时,对于分类任务通常使用简单投票的方式,而对于回归任务使用简单平均法。

自助采样的方式还给Bagging带来了另外一个优点,由于训练集中的某些样本没有在采样集中出现过,这些没有出现在采样集的样本便可以作为验证集使用。通过使用验证集,可以对泛化性能进行“包外估计”,或者是用于模型的超参数优化,决策树的剪枝,神经网络训练的早停,等等。

从偏差-方差分解的角度看,Bagging主要关注的是降低方差,因此这种方法在不剪枝的决策树、神经网络等容易过拟合的学习器上效果更加明显。

代码示例

我们使用Sklearn自带的Diabetes数据集,来演示如何用sklearn中的Bagging做回归任务。这一数据集共有10个特征,且这些特征都已经被标准化至\((-2,2)\)区间内,待预测的值是25-346范围内的整数。由于我们的目的主要是说明模型的用法,因此省略了特征工程的步骤,将这些数据直接用来训练模型。

1
2
3
4
5
6
7
8
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt

from sklearn.datasets import load_diabetes
from sklearn.model_selection import train_test_split
from sklearn.ensemble import BaggingRegressor
from sklearn.linear_model import Ridge
1
2
X,y=load_diabetes(return_X_y=True)
train_x,test_x,train_y,test_y=train_test_split(X,y,test_size=0.3)

BaggingRegressor回归器的主要参数有:

  • base_estimator:Bagging使用的基回归器
  • n_estimators:构造多少个基回归器,默认为10
  • max_samples:在训练基分类器时使用多少训练数据,默认为1.0,代表使用全部数据。可以传入一个整数,对应于具体的数量;或是传入一个0-1的浮点数,表示从训练集中抽取数据的比例
  • max_features:在训练基分类器时使用多少个特征,默认为1.0,代表使用全部特征。可以传入一个整数;或是传入一个0-1的浮点数。
  • bootstrap:是否使用有放回抽样,默认为True
  • bootstrap_features:是否使用有放回地选取特征,默认为False
1
2
3
4
reg=BaggingRegressor(Ridge(),n_estimators=50,max_samples=0.6,max_features=0.8)
reg.fit(train_x,train_y)
pred=reg.predict(test_x)
errors=pred-test_y

相应地,在Sklearn中也提供了BaggingClassifier这种分类器,它的参数与BaggingRegressor回归器基本相同。

随机森林

随机森林是基于Bagging的一个扩展变体,它在以决策树为基学习器构建Bagging集成的基础上,进一步在决策树的训练过程中引入了随机特征选择。具体来说,传统的决策树在选择划分特征时是在当前结点的特征集合中选择一个最优属性;而在随机森林算法中,则是先从特征集合中随机选择一个子集,然后再从子集中选取最优特征进行划分。

通过样本扰动与属性扰动的结合,随机森林中的基学习器实现了更大的多样性,从而使得最终集成的泛化性能相比于使用决策树的Bagging有了进一步的提升。

我们同样使用Sklearn自带的Diabetes数据集,来演示如何用其中的随机森林算法做回归任务。

1
from sklearn.ensemble import RandomForestRegressor
1
2
X,y=load_diabetes(return_X_y=True)
train_x,test_x,train_y,test_y=train_test_split(X,y,test_size=0.3)

RandomForestRegressor回归器的主要参数有:

  • n_estimators:代表生成多少棵决策树,默认为100
  • criterion:代表结点分类的准则,默认为'mse',也可以使用'mae'
  • bootstrap:是否使用有放回抽样,默认为True
  • max_depth、min_samples_split、min_samples_leaf、max_leaf_nodes:与决策回归树相同
1
2
3
4
reg=RandomForestRegressor()
reg.fit(train_x,train_y)
pred=reg.predict(test_x)
errors=pred-test_y

sklearn同样也提供了RandomForestClassifier分类器,用来构造用于分类的随机森林模型。它的参数与RandomForestRegressor回归器大致相同,只是criterion这一参数的值为'gini'(默认)或者'entropy'。

结合策略

我们假定集成包含了\(T\)个基学习器\(\{h_1,h_2,\dots,h_T\}\),其中\(h_i\)在示例\(\boldsymbol{x}\)上的输出为\(h_i(\boldsymbol{x})\)。下面介绍几种对\(h_i\)进行结合的常用策略。

平均法

如果模型的输出为数值型,那么比较常用的一种结合策略是使用平均法,即: \[ H(\boldsymbol{x})=\frac{1}{T}\sum_{i=1}^{T}h_i(\boldsymbol{x}) \] 或是加权平均: \[ H(\boldsymbol{x})=\sum_{i=1}^{T}w_ih_i(\boldsymbol{x}) \] 加权平均法的权重一般是从训练数据中学习而得,例如AdaBoost。但是现实任务中的训练样本通常存在噪声或者不充分,这将使得学到的权重不完全可靠。因此一般来说,如果个体学习器性能相差较大时使用加权平均,而个体学习器性能相近时则使用简单平均法。

投票法

对于分类任务来说,学习器从类别标记集合中预测出一个标记,最常用的方法是使用投票法。而投票法又分为下面几种:

  • 绝对多数投票法:如果某个标记得票过半数,则预测为该标记;否则拒绝预测。
  • 相对多数投票法:预测结果为得票最多的标记;如果同时有多个标记获得最高票,则随机选取一个。
  • 加权投票法:类似于加权平均法,在统计投票的时候为每个学习器赋予一个权重。

sklearn提供了VotingClassifier分类器,可以方便地构造多分类器投票。它的用法如下:

1
2
3
4
5
from sklearn.ensemble import VotingClassifier
voting_clf=VotingClassifier(
estimators=[('lr',log_clf),('rf',rnd_clf),('svc',svm_clf)],
voting='hard'
)

传入estimators的参数为基分类器。voting代表投票最后的选择方式,分为两种投票方式,一种为硬投票(hard),输出值为多个分类器中投票最多的那一个;另一种为软投票,如果每个分类器都能输出一个概率,最后把所有概率加起来并取平均,并从中取概率最高的那个作为分类依据。

学习法

学习法指的是通过另一个学习器将基模型结合起来。其中个体学习器被称为初级学习器,用于结合的学习器称为次级学习器或者元学习器。

Stacking

Stacking是学习法中的一个典型代表,下面我们将对其进行介绍(Stacking本身也属于一种著名的集成学习方法,同时也可以看作是一种特殊的结合策略)。

Stacking先从初始训练集训练出一组初级学习器,然后生成一个新数据集(被称为次级训练集)用于训练次级学习器。在这个新数据集中,初级学习器的输出被当作样例的输入特征,而初始样本的标记仍然被当作样例标记。

由于次级训练集是使用初级学习器产生的,如果直接使用初级学习器的训练集来产生次级训练集,那么会有很大的过拟合风险。因此,一般是通过使用交叉验证法的方式,用训练初级学习器时未使用的样本来产生次级学习器的训练样本。

\(k\)折交叉验证为例,初始训练集\(D\)被随机划分为\(k\)个大小相似的集合\(D_1,D_2,\dots,D_k\)。我们记\(D_j\)\(\bar{D}_j=D\text{\\}D_j\)分别为第\(j\)折的测试集和训练集。我们假定有\(T\)个初级学习算法,其中的每一个算法都要使用\(k\)折的数据训练出\(k\)个学习器,我们将第\(t\)个初级学习算法使用第\(j\)折训练集学习得到的模型记作\(h_t^{(j)}\),这一模型在测试集数据\(\boldsymbol{x}_i\in D_j\)上的预测值\(h_t^{(j)}(\boldsymbol{x}_i)\)记作\(\boldsymbol{z}_{it}\)。则\(\boldsymbol{x}_i\)产生的次级训练样本的特征部分为\(\boldsymbol{z}_i=(\boldsymbol{z}_{i1},\boldsymbol{z}_{i2},\dots,\boldsymbol{z}_{iT})\),标签部分仍然是\(y_i\)。通过这种方式,\(D\)中的每一个样本都能为次级学习器产生一个次级训练样本,样本的每一个特征对应于一个初级学习算法(但是同一个特征中,不同样本的值可能产生自不同的学习器)。

而在预测阶段,对于次级学习器的输入来说,其\(T\)个特征中的每一个都简单地取与之对应的\(k\)个学习器的平均值即可。

根据上面的描述,Stacking产生训练样本以及后续对新数据进行测试的方法如下图所示:

img

最后,我们使用Sklearn自带的Diabetes数据集,来演示如何用sklearn做stacking。

1
2
3
from sklearn.ensemble import StackingRegressor
from sklearn.linear_model import LinearRegression, Ridge, Lasso
from sklearn.svm import LinearSVR
1
2
X,y=load_diabetes(return_X_y=True)
train_x,test_x,train_y,test_y=train_test_split(X,y,test_size=0.3)

StackingRegressor回归器的主要参数有:

  • estimators:代表stacking操作的第一层学习器,需要传入一个list,其中的元素为(str, estimator),即学习器名称与学习器的实体所组成的tuple
  • final_estimator:代表stacking操作的第二层学习器
1
2
3
4
reg=StackingRegressor([('lin_reg',LinearRegression()),('ridge_reg',Ridge()),('lasso_reg',Lasso())],LinearSVR())
reg.fit(train_x,train_y)
pred=reg.predict(test_x)
errors=pred-test_y

与之对应地,同样也有StackingClassifier分类器,可以用于分类任务中的stacking操作。它的参数与StackingRegressor回归器基本相同。

Blending

Blending与Stacking大致相同,只不过Blending是将训练集\(D\)分为\(D_1\)\(D_2\)两部分,其中\(D_1\)用于训练初级学习器,而\(D_2\)用于训练次级学习器。

这种方式实现简单,且不会造成数据泄漏。但是这种方法对训练数据的利用少了,不如Stacking方法稳健,因此适用于数据量较大的情况。

多样性增强

如果我们要构建泛化能力强的集成模型,则需要对基模型引入多样性。增强多样性的常用方法包括但不限于:

  1. 数据样本扰动:给定一个训练集,从中产生不同的数据子集,然后利用不同的数据子集训练出不同的个体学习器。
  2. 输入属性扰动:从初始特征中抽取出不同的特征子集,只使用这些子集来训练基模型。当数据中的特征较多时,这种方法可以产生多样性大的个体,而且可以节省时间开销;但是当数据中的属性较少,或者冗余属性很少的时候则不适合使用这种方法。
  3. 输出表示扰动:这种方法的思路是对训练样本的标签进行操纵以增强多样性。比如可以使用翻转法对一些训练样本的标签进行改动,或是将分类输出转化为回归输出,将原任务拆解为多个可以同时求解的子任务,等等。
  4. 算法参数扰动:基学习算法一般都有一些超参数需要设置,通过为这些基学习算法设置不同的参数,往往就可以产生差别较大的个体学习器。

上述的多样性增强机制可以同时使用,比如随机森林中就同时使用了数据样本扰动和输入属性扰动。

参考

  1. 机器学习,周志华
  2. 统计学习方法,李航
  3. 简述stacking和blending的原理和各自的优劣 - 知乎 (zhihu.com)