集成学习值Adaboost算法原理和代码小结(转载)
在集成学习原理小结中,我们讲到了集成学习按照个体学习器之间是否存在依赖关系可以分为两类:
- 第一个是个体学习器之间存在强依赖关系;
- 另一类是个体学习器之间不存在强依赖关系。
前者的代表算法就是提升(boosting)系列算法。在boosting系列算法中, Adaboost是最著名的算法之一。Adaboost既可以用作分类,也可以用作回归。本文就对Adaboost算法做一个总结。
一 回顾boosting算法的基本原理
AdaBoost是典型的Boosting算法,属于Boosting家族的一员。在说AdaBoost之前,先说说Boosting提升算法。Boosting算法是将“弱学习算法“提升为“强学习算法”的过程,主要思想是“三个臭皮匠顶个诸葛亮”。一般来说,找到弱学习算法要相对容易一些,然后通过反复学习得到一系列弱分类器,组合这些弱分类器得到一个强分类器。Boosting算法要涉及到两个部分,加法模型和前向分步算法。加法模型就是说强分类器由一系列弱分类器线性相加而成。一般组合形式如下:$$f(x;P)=\sum_{k=1}^Kβ_kh(x;\gamma_k)$$
其中,$h(x;\gamma_k)$ 就是一个个的弱分类器,$\gamma_k$是弱分类器学习到的最优参数,$β_k$ 就是弱学习在强分类器中所占比重,$P$ 是所有$\gamma_k$和$\beta_k$ 的组合。这些弱分类器线性相加组成强分类器。
前向分步就是说在训练过程中,下一轮迭代产生的分类器是在上一轮的基础上训练得来的。也就是可以写成这样的形式:
$$f _k(x)=f_{k-1}(x)+ β_kh_k(x;\gamma_k)$$
由于采用的损失函数不同,Boosting算法也因此有了不同的类型,AdaBoost就是损失函数为指数损失的Boosting算法。
在前面一节,我们已经讲到了boosting算法系列的基本思想,如下图:
从图中可以看出,Boosting算法的工作机制是首先从训练集用初始权重D(1)训练出一个弱学习器1,根据弱学习的学习误差率表现来更新训练样本的权重,使得之前弱学习器1学习误差率高的训练样本点的权重变高,使得这些误差率高的点在后面的弱学习器2中得到更多的重视。然后基于调整权重后的训练集来训练弱学习器2.,如此重复进行,直到弱学习器数达到事先指定的数目T,最终将这T个弱学习器通过集合策略进行整合,得到最终的强学习器。
在上图中有几个具体的问题我们没有详细说明。
- 如何计算分类误差率e?
- 如何得到弱学习器权重系数$\alpha$(即上式中的$β_k$)?
- 如何更新训练数据的样本权重D?
- 使用何种结合策略?
只要是boosting大家族的算法,都要解决这4个问题。那么Adaboost是怎么解决的呢?
二 Adaboost算法的基本思想
我们这里讲解Adaboost是如何解决上面4个问题的。
假设我们的训练集样本是:$$T=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$$
训练集的在第k个弱学习器的样本权重系数为:$$D(k) = (w_{k1}, w_{k2}, ...w_{km}) ;\;\;\sum\limits_{i=1}^{m}w_{ki}=1;\;\;w_{1i}=\frac{1}{m};\;\; i =1,2...m$$
注意:在初始化第一个弱分类器输出权重时,我们假设训练集样本具有均匀的权值分布,即每个训练样本在第一个弱分类器的学习中作用相同,这一假设保证可以在训练集样本上学习第一个弱分类器$G_1(x)$。
首先我们看看Adaboost的分类问题。
分类问题的误差率很好理解和计算。由于多元分类是二元分类的推广,这里假设我们是二元分类问题,输出为{-1,1},则第k个弱分类器$G_k(x)$在训练集上的分类误差率为:$$e_k = P(G_k(x_i) \neq y_i) = \sum\limits_{i=1}^{m}w_{ki}I(G_k(x_i) \neq y_i)$$
接着我们看弱学习器权重系数,对于二元分类问题,第k个弱分类器$G_k(x)$的权重系数为:$$\alpha_k = \frac{1}{2}log\frac{1-e_k}{e_k}$$
为什么这样计算弱学习器权重系数?从上式可以看出,如果分类误差率$e_k$越大,则对应的弱分类器权重系数$\alpha_k$越小。也就是说,误差率小的弱分类器权重系数越大。具体为什么采用这个权重系数公式,我们在讲Adaboost的损失函数优化时再讲。
第三个问题,如何更新样本权重D。假设第k个弱分类器的样本集权重系数为$D(k) = (w_{k1}, w_{k2}, ...w_{km})$,则对应的第k+1个弱分类器的样本权重系数为:$$w_{k+1,i} = \frac{w_{ki}}{Z_K}exp(-\alpha_ky_iG_k(x_i))$$
这里$Z_k$是规范化因子:$$Z_k = \sum\limits_{i=1}^{m}w_{ki}exp(-\alpha_ky_iG_k(x_i))$$
从$w_{k+1,i}$计算公式可以看出,如果第i个样本分类错误,则$y_iG_k(x_i) < 0$,导致样本的权重在第k+1个弱分类器中增大,如果分类正确,则权重在第k+1个弱分类器中减少.不改变所给的训练集数据,通过不断的改变训练样本的权重,使得训练集数据在弱分类器的学习中起不同的作用。具体为什么采用这个样本权重更新公式,我们在讲Adaboost的损失函数优化时再讲。
最后一个问题是集合策略。Adaboost分类采用的是加权平均法,最终的强分类器为:$$f(x) = sign(\sum\limits_{k=1}^{K}\alpha_kG_k(x))$$
系数$\alpha_k$表示了弱分类器$G_k(x)$的重要性,这里所有$\alpha$之和并不为1,$f(x)$的符号决定实例$x$的类,$f(x)$的绝对值表示分类的置信度。
接着我们看看Adaboost的回归问题。由于Adaboost的回归问题有很多变种,这里我们以Adaboost R2算法为准。
我们先看看回归问题的误差率的问题,对于第k个弱学习器,计算他在训练集上的最大误差:$$E_k= max|y_i - G_k(x_i)|\;i=1,2...m$$
然后计算每个样本的相对误差$$e_{ki}= \frac{|y_i - G_k(x_i)|}{E_k}$$
这里是误差损失为线性时的情况,如果我们用平方误差,则$e_{ki}= \frac{(y_i - G_k(x_i))^2}{E_k^2}$,如果我们用的是指数误差,则$e_{ki}= 1 - exp(\frac{-y_i + G_k(x_i))}{E_k})$
最终得到第k个弱学习器的 误差率:$$e_k = \sum\limits_{i=1}^{m}w_{ki}e_{ki}$$
我们再来看看如何得到弱学习器权重系数$\alpha$。这里有:$$\alpha_k =\frac{e_k}{1-e_k}$$
对于更新更新样本权重D,第k+1个弱学习器的样本集权重系数为:$$w_{k+1,i} = \frac{w_{ki}}{Z_k}\alpha_k^{1-e_{ki}}$$
这里$Z_k$是规范化因子:$$Z_k = \sum\limits_{i=1}^{m}w_{ki}\alpha_k^{1-e_{ki}}$$
最后是结合策略,和分类问题稍有不同,采用的是对加权的弱学习器取中位数的方法,最终的强回归器为:$$f(x) = \sum\limits_{k=1}^{K}(ln\frac{1}{\alpha_k})g(x)$$
其中,$g(x)$是所有$\alpha_kG_k(x), k=1,2,....K$的中位数。
三 AdaBoost分类问题的损失函数优化
上面我们讲到了分类Adaboost的弱学习器权重系数公式和样本权重更新公式。但是没有解释选择这个公式的原因,让人觉得是魔法公式一样。其实它可以从Adaboost的损失函数推导出来。
从另一个角度讲,Adaboost是模型为加法模型,学习算法为前向分步学习算法,损失函数为指数函数的分类问题。
模型为加法模型好理解,我们的最终的强分类器是若干个弱分类器加权平均而得到的。
前向分步学习算法也好理解,我们的算法是通过一轮轮的弱学习器学习,利用前一个弱学习器的结果来更新后一个弱学习器的训练集权重。也就是说,第k-1轮的强学习器为:$$f_{k-1}(x) = \sum\limits_{i=1}^{k-1}\alpha_iG_{i}(x)$$
而第k轮的强学习器为:$$f_{k}(x) = \sum\limits_{i=1}^{k}\alpha_iG_{i}(x)$$
上两式一比较可以得到:$$f_{k}(x) = f_{k-1}(x) + \alpha_kG_k(x) $$
可见强学习器的确是通过前向分步学习算法一步步而得到的。
Adaboost损失函数为指数函数,即定义损失函数为:$$loss=\sum\limits_{i=1}^{m}exp(-y_if_{k}(x_i))$$
利用前向分步学习算法的关系可以得到损失函数为:$$loss=\sum\limits_{i=1}^{m}exp[-y_i(f_{k-1}(x_i) + \alpha_kG_k(x_i))]$$
假设已经经过了$k-1$次迭代,$f_{k-1}(x)$已知,令$w_{ki}^{’} = exp(-y_if_{k-1}(x_i))$, $w_{ki}^{’}$依赖于$f_{k-1}(x_i)$。
将$w_{ki}^{’}$带入损失函数,损失函数转化为:$$loss=\sum\limits_{i=1}^{m}w_{ki}^{’}exp[-y_i\alpha_k G_k(x_i)]$$我们继续化简$loss$:$$loss=\sum\limits_{y_i=G_k(x_i)}w_{ki}^{'}exp(-\alpha_k)+\sum\limits_{y_i \neq G_k(x_i)}w_{ki}^{'}exp(\alpha_k)$$
$$=(exp(\alpha_k)-exp(-\alpha_k))\sum\limits_{i=1}^{m}w_{ki}^{'}I(y_i \neq G_k(x_i))+exp(-\alpha_k)\sum\limits_{i=1}^{m}w_{ki}^{'}$$
并对$\alpha$求导,使其等于0,则就得到了:$$\alpha_k = \frac{1}{2}log\frac{1-e_k}{e_k}$$
其中,$e_k$即为我们前面的分类误差率。$$e_k = \frac{\sum\limits_{i=1}^{m}w_{ki}^{’}I(y_i \neq G(x_i))}{\sum\limits_{i=1}^{m}w_{ki}^{’}} = \sum\limits_{i=1}^{m}w_{ki}I(y_i \neq G(x_i))$$
最后看样本权重的更新。利用$f_{k}(x) = f_{k-1}(x) + \alpha_kG_k(x) $和$w_{ki}^{’} = exp(-y_if_{k-1}(x))$,即可得:$$w_{k+1,i}^{’} = w_{ki}^{’}exp[-y_i\alpha_kG_k(x)]$$
这与我们上面说到的样本权重的更新只差一个规范化因子$Z_k$,两者是等价的。
四 AdaBoost二元分类问题算法流程
这里我们对AdaBoost二元分类问题算法流程做一个总结。
输入为样本集$T=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$,输出为{-1, +1},弱分类器算法, 弱分类器迭代次数K。
输出为最终的强分类器$f(x)$
1) 初始化样本集权重为:$$D(1) = (w_{11}, w_{12}, ...w_{1m}) ;\;\; w_{1i}=\frac{1}{m};\;\; i =1,2...m$$
2) 对于k=1,2,...K:
a) 使用具有权重$D_k$的样本集来训练数据,得到弱分类器$G_k(x)$
b)计算$G_k(x)$的分类误差率:$$e_k = P(G_k(x_i) \neq y_i) = \sum\limits_{i=1}^{m}w_{ki}I(G_k(x_i) \neq y_i)$$
c) 计算弱分类器的系数:$$\alpha_k = \frac{1}{2}log\frac{1-e_k}{e_k}$$
d) 更新样本集的权重分布:$$w_{k+1,i} = \frac{w_{ki}}{Z_K}exp(-\alpha_ky_iG_k(x_i)) \;\; i =1,2,...m$$
这里$Z_k$是规范化因子:$$Z_k = \sum\limits_{i=1}^{m}w_{ki}exp(-\alpha_ky_iG_k(x_i))$$
3) 构建最终分类器为:$$f(x) = sign(\sum\limits_{k=1}^{K}\alpha_kG_k(x))$$
对于Adaboost多元分类算法,其实原理和二元分类类似,最主要区别在弱分类器的系数上。比如Adaboost SAMME算法,它的弱分类器的系数:$$\alpha_k = \frac{1}{2}log\frac{1-e_k}{e_k} + log(R-1)$$
其中R为类别数。从上式可以看出,如果是二元分类,R=2,则上式和我们的二元分类算法中的弱分类器的系数一致。
五 Adaboost回归问题的算法流程
这里我们对AdaBoost回归问题算法流程做一个总结。AdaBoost回归算法变种很多,下面的算法为Adaboost R2回归算法过程。
输入为样本集$T=\{(x_,y_1),(x_2,y_2), ...(x_m,y_m)\}$,,弱学习器算法, 弱学习器迭代次数K。
输出为最终的强学习器$f(x)$
1) 初始化样本集权重为:$$D(1) = (w_{11}, w_{12}, ...w_{1m}) ;\;\; w_{1i}=\frac{1}{m};\;\; i =1,2...m$$
2) 对于k=1,2,...K:
a) 使用具有权重$D_k$的样本集来训练数据,得到弱学习器$G_k(x)$
b) 计算训练集上的最大误差:$$E_k= max|y_i - G_k(x_i)|\;i=1,2...m$$
c) 计算每个样本的相对误差:
如果是线性误差,则$e_{ki}= \frac{|y_i - G_k(x_i)|}{E_k}$;
如果是平方误差,则$e_{ki}= \frac{(y_i - G_k(x_i))^2}{E_k^2}$
如果是指数误差,则$e_{ki}= 1 - exp(\frac{-|y_i -G_k(x_i)|}{E_k})$
d) 计算回归误差率:$$e_k = \sum\limits_{i=1}^{m}w_{ki}e_{ki}$$
e) 计算弱学习器的系数:$$\alpha_k =\frac{e_k}{1-e_k}$$
f) 更新样本集的权重分布为:$$w_{k+1,i} = \frac{w_{ki}}{Z_k}\alpha_k^{1-e_{ki}}$$
这里$Z_k$是规范化因子:$$Z_k = \sum\limits_{i=1}^{m}w_{ki}\alpha_k^{1-e_{ki}}$$
3) 构建最终强学习器为:$$f(x) = \sum\limits_{k=1}^{K}(ln\frac{1}{\alpha_k})g(x)$$
其中,$g(x)$是所有$\alpha_kG_k(x), k=1,2,....K$的中位数。
六 Adaboost算法的正则化
为了防止Adaboost过拟合,我们通常也会加入正则化项,这个正则化项我们通常称为步长(learning rate)。定义为$\nu$,对于前面的弱学习器的迭代:$$f_{k}(x) = f_{k-1}(x) + \alpha_kG_k(x) $$
如果我们加上了正则化项,则有:$$f_{k}(x) = f_{k-1}(x) + \nu\alpha_kG_k(x) $$
$\nu$的取值范围为$0 < \nu \leq 1 $。对于同样的训练集学习效果,较小的$\nu$意味着我们需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起来决定算法的拟合效果。
七 Adaboost的例子
给定如下表所示训练数据,假设弱分类器由$x<v$或$x>v$产生,可以看做由一个根节点直接连接两个叶节点的简单决策树,其阈值$v$使该分类器在训练数据集上的分类误差率最低,试用Adaboost算法学习一个强分类器。
序号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
$x$ | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
$y$ | 1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | -1 |
解:初始化样本权重系数:$$D_1={w_{11},w_{12},...,w_{110}};\;\;w_{1i}=0.1,i=1,2,...,10$$
对于$k$=1:
a、在权重为$D_1$的训练数据上、阈值$v$取2.5时分类误差率最低,故弱分类器为:$$G_1(x)=\begin{cases}1, { x<2.5}\\ - 1, {x>2.5 }\end{cases}$$
b、$G_1(x)$在训练数据集上的分类误差率$e_1=P(G_1(x_i) \neq y_i) = 0.3$
c、计算$G_1(x)$的系数:$\alpha_1=\frac{1}{2}log\frac{1-e_1}{e_1}=0.4236$
d、更新样本的权重分布:$$D_2={w_{21},...,w_{2i},...,w_{210}};\;\;w_{2i}=\frac{w_{1i}}{Z_1}exp(-\alpha_1 y_i G_1(x_i)), i=1,2,...,10$$ $$D_2=(0.07143,0.07143,0.07143,0.07143,0.07143,0.07143,0.16667,0.16667,0.16667,0.07143)$$ $$f_1(x)=0.4236G_1(x)$$
分类器$sign[f_1(x)]$在训练数据集上有3个误分类点。
对于$k$=2:
a、在权重为$D_2$的训练数据上、阈值$v$取8.5时分类误差率最低,故弱分类器为:$$G_2(x)=\begin{cases}1, { x<8.5}\\ - 1, {x>8.5 }\end{cases}$$
b、$G_2(x)$在训练数据集上的分类误差率$e_2=P(G_2(x_i) \neq y_i) = 0.2143$
c、计算$G_2(x)$的系数:$\alpha_2=\frac{1}{2}log\frac{1-e_2}{e_2}=0.6496$
d、更新样本的权重分布:$$D_3={w_{31},...,w_{3i},...,w_{310}};\;\;w_{3i}=\frac{w_{2i}}{Z_2}exp(-\alpha_2 y_i G_2(x_i)), i=1,2,...,10$$ $$D_3=(0.0455,0.0455,0.0455,0.1667,0.1667,0.1667,0.1060,0.1060,0.1060,0.0455)$$ $$f_2(x)=0.4236G_1(x)+0.6496G_2(x)$$
分类器$sign[f_2(x)]$在训练数据集上有3个误分类点。
对于$k$=3:
a、在权重为$D_3$的训练数据上、阈值$v$取5.5时分类误差率最低,故弱分类器为:$$G_3(x)=\begin{cases}1, { x>5.5}\\ - 1, {x<5.5 }\end{cases}$$
b、$G_3(x)$在训练数据集上的分类误差率$e_3=P(G_3(x_i) \neq y_i) = 0.1820$
c、计算$G_3(x)$的系数:$\alpha_3=\frac{1}{2}log\frac{1-e_3}{e_3}=0.7514$
d、更新样本的权重分布:$$D_4={w_{41},...,w_{4i},...,w_{410}};\;\;w_{4i}=\frac{w_{3i}}{Z_3}exp(-\alpha_3 y_i G_3(x_i)), i=1,2,...,10$$ $$D_4=(0.125,0.125,0.125,0.102,0.102,0.102,0.065,0.065,0.065,0.125)$$ $$f_3(x)=0.4236G_1(x)+0.6496G_2(x)+0.7514G_3(x)$$
分类器$sign[f_3(x)]$在训练数据集上有0个误分类点。
于是最终分类器为:$$G(x)=sign[f_3(x)]=sign[0.4236G_1(x)+0.6496G_2(x)+0.7514G_3(x)]$$
八 scikit-learn Adaboost类库使用小结
1. Adaboost类库概述
scikit-learn中Adaboost类库比较直接,就是AdaBoostClassifier和AdaBoostRegressor两个,从名字就可以看出AdaBoostClassifier用于分类,AdaBoostRegressor用于回归。
AdaBoostClassifier使用了两种Adaboost分类算法的实现,SAMME和SAMME.R。而AdaBoostRegressor则使用了讲到的Adaboost回归算法的实现,即Adaboost.R2。
当我们对Adaboost调参时,主要要对两部分内容进行调参,第一部分是对我们的Adaboost的框架进行调参, 第二部分是对我们选择的弱分类器进行调参。两者相辅相成。下面就对Adaboost的两个类:AdaBoostClassifier和AdaBoostRegressor从这两部分做一个介绍。
2. AdaBoostClassifier和AdaBoostRegressor框架参数
我们首先来看看AdaBoostClassifier和AdaBoostRegressor框架参数。两者大部分框架参数相同,下面我们一起讨论这些参数,两个类如果有不同点我们会指出。
1)base_estimator:AdaBoostClassifier和AdaBoostRegressor都有,即我们的弱分类学习器或者弱回归学习器。理论上可以选择任何一个分类或者回归学习器,不过需要支持样本权重。我们常用的一般是CART决策树或者神经网络MLP。默认是决策树,即AdaBoostClassifier默认使用CART分类树DecisionTreeClassifier,而AdaBoostRegressor默认使用CART回归树DecisionTreeRegressor。另外有一个要注意的点是,如果我们选择的AdaBoostClassifier算法是SAMME.R,则我们的弱分类学习器还需要支持概率预测,也就是在scikit-learn中弱分类学习器对应的预测方法除了predict还需要有predict_proba。
2)algorithm:这个参数只有AdaBoostClassifier有。主要原因是scikit-learn实现了两种Adaboost分类算法,SAMME和SAMME.R。两者的主要区别是弱学习器权重的度量,SAMME使用了和我们的原理篇里二元分类Adaboost算法的扩展,即用对样本集分类效果作为弱学习器权重,而SAMME.R使用了对样本集分类的预测概率大小来作为弱学习器权重。由于SAMME.R使用了概率度量的连续值,迭代一般比SAMME快,因此AdaBoostClassifier的默认算法algorithm的值也是SAMME.R。我们一般使用默认的SAMME.R就够了,但是要注意的是使用了SAMME.R, 则弱分类学习器参数base_estimator必须限制使用支持概率预测的分类器。SAMME算法则没有这个限制。
3)loss:这个参数只有AdaBoostRegressor有,Adaboost.R2算法需要用到。有线性‘linear’, 平方‘square’和指数 ‘exponential’三种选择, 默认是线性,一般使用线性就足够了,除非你怀疑这个参数导致拟合程度不好。这个值的意义在原理中我们也讲到了,它对应了我们对第k个弱分类器的中第i个样本的误差的处理,即:如果是线性误差,则$e_{ki}= \frac{|y_i - G_k(x_i)|}{E_k}$;如果是平方误差,则$e_{ki}= \frac{(y_i - G_k(x_i))^2}{E_k^2}$,如果是指数误差,则$e_{ki}= 1 - exp(\frac{-y_i + G_k(x_i))}{E_k})$,$E_k$为训练集上的最大误差$E_k= max|y_i - G_k(x_i)|\;i=1,2...m$
4) n_estimators: AdaBoostClassifier和AdaBoostRegressor都有,就是我们的弱学习器的最大迭代次数,或者说最大的弱学习器的个数。一般来说n_estimators太小,容易欠拟合,n_estimators太大,又容易过拟合,一般选择一个适中的数值。默认是50。在实际调参的过程中,我们常常将n_estimators和下面介绍的参数learning_rate一起考虑。
5) learning_rate: AdaBoostClassifier和AdaBoostRegressor都有,即每个弱学习器的权重缩减系数$\nu$,在原理中的正则化小节我们也讲到了,加上了正则化项,我们的强学习器的迭代公式为$f_{k}(x) = f_{k-1}(x) + \nu\alpha_kG_k(x) $。$\nu$的取值范围为$0 < \nu \leq 1 $。对于同样的训练集拟合效果,较小的$\nu$意味着我们需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起来决定算法的拟合效果。所以这两个参数n_estimators和learning_rate要一起调参。一般来说,可以从一个小一点的$\nu$开始调参,默认是1。
3. AdaBoostClassifier和AdaBoostRegressor弱学习器参数
这里我们再讨论下AdaBoostClassifier和AdaBoostRegressor弱学习器参数,由于使用不同的弱学习器,则对应的弱学习器参数各不相同。这里我们仅仅讨论默认的决策树弱学习器的参数。即CART分类树DecisionTreeClassifier和CART回归树DecisionTreeRegressor。
DecisionTreeClassifier和DecisionTreeRegressor的参数基本类似,在scikit-learn决策树算法类库使用小结这篇文章中我们对这两个类的参数做了详细的解释。这里我们只拿出调参数时需要尤其注意的最重要几个的参数再拿出来说一遍:
1) 划分时考虑的最大特征数max_features: 可以使用很多种类型的值,默认是"None",意味着划分时考虑所有的特征数;如果是"log2"意味着划分时最多考虑log
个特征;如果是"sqrt"或者"auto"意味着划分时最多考虑$log_2N$个特征。如果是整数,代表考虑的特征绝对数。如果是浮点数,代表考虑特征百分比,即考虑(百分比xN)取整后的特征数。其中N为样本总特征数。一般来说,如果样本特征数不多,比如小于50,我们用默认的"None"就可以了,如果特征数非常多,我们可以灵活使用刚才描述的其他取值来控制划分时考虑的最大特征数,以控制决策树的生成时间。
2) 决策树最大深max_depth: 默认可以不输入,如果不输入的话,决策树在建立子树的时候不会限制子树的深度。一般来说,数据少或者特征少的时候可以不管这个值。如果模型样本量多,特征也多的情况下,推荐限制这个最大深度,具体的取值取决于数据的分布。常用的可以取值10-100之间。
3) 内部节点再划分所需最小样本数min_samples_split: 这个值限制了子树继续划分的条件,如果某节点的样本数少于min_samples_split,则不会继续再尝试选择最优特征来进行划分。 默认是2.如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
4) 叶子节点最少样本数min_samples_leaf: 这个值限制了叶子节点最少的样本数,如果某叶子节点数目小于样本数,则会和兄弟节点一起被剪枝。 默认是1,可以输入最少的样本数的整数,或者最少样本数占样本总数的百分比。如果样本量不大,不需要管这个值。如果样本量数量级非常大,则推荐增大这个值。
5)叶子节点最小的样本权重和min_weight_fraction_leaf:这个值限制了叶子节点所有样本权重和的最小值,如果小于这个值,则会和兄弟节点一起被剪枝。 默认是0,就是不考虑权重问题。一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引入样本权重,这时我们就要注意这个值了。
6) 最大叶子节点数max_leaf_nodes: 通过限制最大叶子节点数,可以防止过拟合,默认是"None”,即不限制最大的叶子节点数。如果加了限制,算法会建立在最大叶子节点数内最优的决策树。如果特征不多,可以不考虑这个值,但是如果特征分成多的话,可以加以限制,具体的值可以通过交叉验证得到。
4. AdaBoostClassifier实战
这里我们用一个具体的例子来讲解AdaBoostClassifier的使用。
首先我们载入需要的类库:
import numpy as np import matplotlib.pyplot as plt %matplotlib inline from sklearn.ensemble import AdaBoostClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.datasets import make_gaussian_quantiles
接着我们生成一些随机数据来做二元分类,如果对如何产生随机数据不熟悉,在另一篇文章机器学习算法的随机数据生成中有比较详细的介绍。
# 生成2维正态分布,生成的数据按分位数分为两类,500个样本,2个样本特征,协方差系数为2 X1, y1 = make_gaussian_quantiles(cov=2.0,n_samples=500, n_features=2,n_classes=2, random_state=1) # 生成2维正态分布,生成的数据按分位数分为两类,400个样本,2个样本特征均值都为3,协方差系数为2 X2, y2 = make_gaussian_quantiles(mean=(3, 3), cov=1.5,n_samples=400, n_features=2, n_classes=2, random_state=1) #讲两组数据合成一组数据 X = np.concatenate((X1, X2)) y = np.concatenate((y1, - y2 + 1))
我们通过可视化看看我们的分类数据,它有两个特征,两个输出类别,用颜色区别。
plt.scatter(X[:, 0], X[:, 1], marker='o', c=y,s=10)
可以看到数据有些混杂,我们现在用基于决策树的Adaboost来做分类拟合。
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME", n_estimators=200, learning_rate=0.8) bdt.fit(X, y)
这里我们选择了SAMME算法,最多200个弱分类器,步长0.8,在实际运用中你可能需要通过交叉验证调参而选择最好的参数。拟合完了后,我们用网格图来看看它拟合的区域。并把拟合的区域用轮廓绘制出来。
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) Z = bdt.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) cs = plt.contourf(xx, yy, Z, cmap=plt.cm.Paired) plt.scatter(X[:, 0], X[:, 1], marker='o', c=y) plt.show()
从图中可以看出,我们的样本数据集基本上被轮廓分割开来,Adaboost的拟合效果还是不错的,现在我们看看拟合分数:
print('Score:',bdt.score(X,y))
也就是说拟合训练集数据的分数还不错。当然分数高并不一定好,因为可能过拟合。
现在我们将最大弱分离器个数从200增加到300。再来看看拟合分数。
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME", n_estimators=300, learning_rate=0.8) bdt.fit(X, y) print("Score:", bdt.score(X,y))
此时的输出为:Score: 0.962222222222
这印证了我们前面讲的,弱分离器个数越多,则拟合程度越好,当然也越容易过拟合。
现在我们降低步长,将步长从上面的0.8减少到0.5,再来看看拟合分数。
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME", n_estimators=300, learning_rate=0.5) bdt.fit(X, y) print("Score:", bdt.score(X,y))
此时的输出为:Score: 0.894444444444
可见在同样的弱分类器的个数情况下,如果减少步长,拟合效果会下降。
最后我们看看当弱分类器个数为700,步长为0.7时候的情况:
bdt = AdaBoostClassifier(DecisionTreeClassifier(max_depth=2, min_samples_split=20, min_samples_leaf=5), algorithm="SAMME", n_estimators=600, learning_rate=0.7) bdt.fit(X, y) print("Score:", bdt.score(X,y))
此时的输出为:Score: 0.961111111111
此时的拟合分数和我们最初的300弱分类器,0.8步长的拟合程度相当。也就是说,在我们这个例子中,如果步长从0.8降到0.7,则弱分类器个数要从300增加到700才能达到类似的拟合效果。
九 Adaboost小结
到这里Adaboost就写完了,前面有一个没有提到,就是弱学习器的类型。理论上任何学习器都可以用于Adaboost.但一般来说,使用最广泛的Adaboost弱学习器是决策树和神经网络。对于决策树,Adaboost分类用了CART分类树,而Adaboost回归用了CART回归树。
这里对Adaboost算法的优缺点做一个总结。
Adaboost的主要优点有:
- Adaboost作为分类器时,分类精度很高
- 在Adaboost的框架下,可以使用各种回归分类模型来构建弱学习器,非常灵活。
- 作为简单的二元分类器时,构造简单,结果可理解。
- 不容易发生过拟合
Adaboost的主要缺点有:
- 对异常样本敏感,异常样本在迭代中可能会获得较高的权重,影响最终的强学习器的预测准确性。
参考文章
[2]scikit-learn Adaboost类库使用小结
[3]AdaBoost原理详解
[5]统计学习方法.李航