欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

集成学习

程序员文章站 2022-07-09 19:51:47
...

集成学习

这篇博客是在学习集成学习时总结多篇博客和文章,再加上自己一些看法和补充的结果。具体参考的博客和文章见文末参考文献。

集成学习概述

集成学习(Ensemble learing)是使用一系列学习器进行学习,并使用某种规则把各个学习结果进行整合从而获得比单个学习器效果更好的一种机器学习方法。对于训练数据,我们通过若干个个体学习器,通过一定的聚合策略,就可以形成一个强学习器,以达到博采众长的目的。

也就是说,集成学习主要有两个问题,一是如何得到若干个个体学习器,二是如何选择一种结合策略,将这些弱学习器集成强学习器。

集成学习之个体学习器

个体学习器有两种选择。一种是所有个体学习器是一个种类的,或者说是同质的,比如都是决策树或者神经网络。另一种是所有个体学习器不全是一个种类的,或者说是异质的,比如对训练集采用KNN,决策树,逻辑回归,朴素贝叶斯或者SVM等,再通过结合策略来集成。

目前来说,同质的个体学习器应用最广泛,一般我们常说的集成方法都是同质个体学习器。而同质学习器使用最多的是CART决策树和神经网络。另外,个体学习器之间是否存在依赖关系可以将集成方法分为两类。一类是个体学习器之间存在强依赖关系,即串行,代表算法是boosting系列算法(Adaboost和GBDT),另一类是个体学习器之间不存在依赖关系,即并行,代表算法是bagging和随机森林。下面分别对这两类算法做一个总结。

集成学习之boosting

boosting算法的工作机制是给每一个样本分配一个初始权重,然后用训练样本和权重训练处弱分类器1,根据弱分类器1更新样本的权重,再训练弱分类器2,如此重复进行,直到学习器达到指定的数目,最终将这些弱学习器集成强学习器。可以看出各个弱分类器之间是串行的。

boosting系列算法中最著名的是有Adaboost和提升树(boosting tree),提升树中应用最广泛的是GBDT(梯度提升树)。

集成学习之bagging

bagging算法的各个弱分类器是并行的,相互之间没有影响,可以单独训练。但是单个学习器的训练数据是不一样的。假设原始数据中有n个样本,有T个弱学习器,在原始数据中进行T次有放回的随机采样,得到T个新数据集,作为每个弱分类器的训练样本,新数据集和原始数据集的大小相等。每一个新数据集都是在原始数据集中有放回的选择n个样本得到的。

随机森林是bagging的一个特化进阶版,特化是指随机森林的弱学习器都是决策树,进阶是指随机森林在bagging的基础上,又加上了特征的随机选择,其基本思想和bagging一致。

集成学习之弱学习器集合策略

在上面几节中主要关注弱学习器,但是没有说学习器如何结合。假定我们有T个若学习器{h1,h2hT}{h1,h2,hT}

  1. 对于回归的平均法:对于回归问题,通常使用的是平均法,也就是说将T个弱学习器的输出进行平均作为最终的预测输出。最简单的是算数平均H(x)=1TTi=1hi(x)H(x)=1T∑i=1Thi(x)。也可使用加权平均,如果每一个学习器都有自己的权重wi,wi0,Ti=1wi=1wi,wi≥0,∑i=1Twi=1,则最终的预测结果是H(x)=Ti=1wihi(x)H(x)=∑i=1Twihi(x)
  2. 对于分类的投票法:对于分类问题最常用的是投票法。最简单的是多数投票法,也就是T个学习器对样本都有自己的预测类别,数量最多的类别作为最终的分类结果。如果不只一个类别获得最高票,则随机选择一个。稍微复杂一些的是过半投票法,在多数投票法的基础上,不仅要最高票,还需要票数过半,否则拒绝预测。更加复杂的是加权投票法,每个弱学习器都有自己的权重,最终将各个类别加权求和,最大的值对应的类别作为最终类别。
  3. 学习法:上面两种方法将弱学习器的结果做平均,相对比较简单,可能学习误差较大,于是就有了学习法,代表方法是stacking。当使用stacking的结合策略时,我们不是对弱学习器的结果做简单的处理,而是加上了一层学习器。将弱学习的结果作为输入,重新训练一个学习器得到最终的结果。

以上是集成学习的框架,接下来要学习三种集成学习的具体算法,有boosting算法中的Adaboost和GBDT以及bagging中的随机森林。

偏差和方差

经常听到一种税法,bagging是减少variance,而boosting是减少bias?。那么什么是模型的方差和偏差呢?又为什么会有这种说法呢?

理解偏差和方差可以提高模型的准确率。我们从三方面定义偏差和方差:概念,图形和数学

  1. 概念

    偏差是模型的平均预测的目标值和真实目标值之间的差距。差距小,则偏差小,差距大,则偏差大。得到的是模型的准确性。

    方差是给定样本点,通过模型得到该样本点目标值的变化情况。如果多次得到的预测值变化小,则方差小,反之,则方差大。得到的是模型的确定性。

    当然,只有一个模型是不能得到预测值的平均情况和变化情况的。通常测量模型的偏差和方差是通过k折交叉验证得到的。

  2. 图形

    结合偏差和方差的各种情况,可以得到如下图示

    集成学习

    图中的红色靶心表示样本的真实目标值,蓝色离散点表示样本经过模型在交叉验证中得到多次预测值。第一行表示低偏差,预测值的平均离靶心很近,第二行是高偏差,预测值的平均离靶心较远。左一列是低方差,多次得到的预测值变化不明显,确定性高,右一列是高方差,多次得到的预测值变化明显,确定性低。

  3. 数学

    给定样本X和目标值Y,模型试图建立X和Y之间的关系Y=f(x)+ϵY=f(x)+ϵ。假设我们得到了f(x)f(x)的估计f^(x)f^(x),则均方误差为

    Err(x)=E[(Yf^(x))2]=E[(YE[f^(x)]+E[f^(x)]f^(x))2]=E[(YE[f^(x)])2+(E[f^(x)]f^(x))2+2(YE[f^(x)])(E[f^(x)]f^(x))]=(YE[f^(x)])2+E[(E[f^(x)]f^(x))2]+σ=Bias2+Variance+noiseErr(x)=E[(Y−f^(x))2]=E[(Y−E[f^(x)]+E[f^(x)]−f^(x))2]=E[(Y−E[f^(x)])2+(E[f^(x)]−f^(x))2+2(Y−E[f^(x)])(E[f^(x)]−f^(x))]=(Y−E[f^(x)])2+E[(E[f^(x)]−f^(x))2]+σ=Bias2+Variance+noise

    可以看出,模型的误差是有三部分组成的,偏差,方差和噪声。其中噪声是数据本身的噪声,表示当前任务在任何学习算法上所能达到的期望泛化误差的下界,刻画了学习问题本身的难度。所以说要降低一个模型的泛化误差需要使偏差和方差都达到最小。

    但通常情况下,偏差度量了学习算法的期望预测值和真实结果的偏离程度,刻画了学习算法本身的拟合能力,要使得偏差小,模型通常会过拟合,便会导致方差大。所以说模型的泛化误差是偏差和方差的折中。

一般来讲,bias高时underfit的表现,variance高时overfit的表现。一个模型的泛化能力很差,即利用训练数据训练好一个模型后,将其用于测试数据集,得到的误差很高,则说明这个模型是underfit或者overfit的。

那么遇到这种情况应该怎样解决呢?有以下解决方案列表:

  1. 获得更多的训练数据,修正过拟合。增加训练数据对于过拟合是有所改善的,但是对于欠拟合是没有用的;
  2. 尝试使用较少的特征,修正过拟合。可以使特征的参数稀疏,或者使用正则化;
  3. 增加正则项系数,修正过拟合
  4. 使用更多的特征,修正欠拟合
  5. 使用非线性模型,修正欠拟合
  6. 减小正则化系数,修正欠拟合

理解了偏差和方差,现在来看集成学习中的一句话,“bagging是减少variance,而boosting是减少bias?”。

我们常说集成学习框架中的基模型是弱模型,通常来说弱模型是偏差高(在训练集上准确度低)方差小(防止过拟合能力强)的模型。但是,并不是所有集成学习框架中的基模型都是弱模型。bagging和stacking中的基模型为强模型(偏差低方差高),boosting中的基模型为弱模型。

在bagging和boosting框架中,通过计算基模型的期望和方差,我们可以得到模型整体的期望和方差。为了简化模型,我们假设基模型的权重、方差及两两间的相关系数相等。由于bagging和boosting的基模型都是线性组成的,那么有:

集成学习

对于boosting来说,基模型的训练集抽样是强相关的,那么模型的相关系数近似等于1,故我们也可以针对boosting化简公式为:

集成学习

通过观察整体方差的表达式,我们容易发现,若基模型不是弱模型,其方差相对较大,这将导致整体模型的方差很大,即无法达到防止过拟合的效果。因此,boosting框架中的基模型必须为弱模型。

因为基模型为弱模型,导致了每个基模型的准确度都不是很高(因为其在训练集上的准确度不高)。随着基模型数的增多,整体模型的期望值增加,更接近真实值,因此,整体模型的准确度提高。但是准确度一定会无限逼近于1吗?仍然并不一定,因为训练过程中准确度的提高的主要功臣是整体模型在训练集上的准确度提高,而随着训练的进行,整体模型的方差变大,导致防止过拟合的能力变弱,最终导致了准确度反而有所下降。

基于boosting框架的Gradient Tree Boosting模型中基模型也为树模型,同Random Forrest,我们也可以对特征进行随机抽样来使基模型间的相关性降低,从而达到减少方差的效果。

对于bagging来说,每个基模型的权重等于1/m且期望近似相等(子训练集都是从原训练集中进行子抽样),故我们可以进一步化简得到: 
集成学习 
根据上式我们可以看到,整体模型的期望近似于基模型的期望,这也就意味着整体模型的偏差和基模型的偏差近似。同时,整体模型的方差小于等于基模型的方差(当相关性为1时取等号),随着基模型数(m)的增多,整体模型的方差减少,从而防止过拟合的能力增强,模型的准确度得到提高。但是,模型的准确度一定会无限逼近于1吗?并不一定,当基模型数增加到一定程度时,方差公式第二项的改变对整体方差的作用很小,防止过拟合的能力达到极限,这便是准确度的极限了。另外,在此我们还知道了为什么bagging中的基模型一定要为强模型,否则就会导致整体模型的偏差度低,即准确度低。

Random Forest是典型的基于bagging框架的模型,其在bagging的基础上,进一步降低了模型的方差。Random Fores中基模型是树模型,在树的内部节点分裂过程中,不再是将所有特征,而是随机抽样一部分特征纳入分裂的候选项。这样一来,基模型之间的相关性降低,从而在方差公式中,第一项显著减少,第二项稍微增加,整体方差仍是减少。

那么子模型之间的相关性是如何度量的呢?这里主要从样本抽样的角度理解。在boosting中,个子模型的样本一样,所以相关性为1。在bagging中有随机抽样的过程,如果每次抽样的样本完全不重复,则说子模型完全独立,相关性为0,。但是在bagging算法和随机森林中的随机抽样得到的数据集不是完全独立的,总是有重合的,所以此时的相关性介于前两种情况中间,具有一定的相关子那个。从bagging的方差公式中可以看出,当相关性减小是,可以减小整体模型的方差。

综上所述,boosting的弱学习器是高偏差低方差的,因为boosting算法不能减小方差,只能通过集成的策略减小偏差,整体模型的方差依赖于弱学习器的方差,所以弱学习器的方差要小。bagging的弱学习器是低偏差高方差的,因为bagging算法不能改变弱学习器的偏差,但是通过集成策略能显著减小方差,所以其弱学习器的偏差要小,可以过拟合。

boosting之Adaboost

boosting算法的基本思想如下图:

集成学习

从图中可以看出,boosting算法的工作机制是先初始化样本的权重,利用样本和权重训练出一个弱学习器1,根据弱学习器的学习误差率更新权重系数,利用权重系数更新样本权重,然后基于更新后的权重和样本训练弱学习器2,重复以上的过程,指代弱学习器的个数达到指定的数目,最终将这些弱学习器集成,得到强学习器。

所以boosting算法中有以下几个问题需要解决:

  1. 如何训练弱学习器
  2. 如何计算学习误差率ee
  3. 如何更新弱学习器权重系数αα
  4. 如何更新样本权重DD
  5. 使用哪一种集成策略

只要是boosting大家族的算法,都要解决以上5个问题。

Adaboost二分类算法的基本流程

这里主要解决以上5个问题

假设训练集是T={(x1,y1),(x2,y2),...,(xn,yn)}T={(x1,y1),(x2,y2),...,(xn,yn)},训练集在第k个弱学习器上的样本权重是[wk1,wk2,...,wkn],w1i=1n,i=1,2,...,n[wk1,wk2,...,wkn],w1i=1n,i=1,2,...,n,即第一个弱分类器的样本权重是自定义的。

输入:训练数据集T,弱学习算法和弱学习器个数T

输出:最终的强分类器f(x)f(x)

  1. 初始化样本权重D1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,nD1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,n

  2. m=1,2,...,Tm=1,2,...,T

    • 使用具有样本权重DmDm的训练数据和弱学习器算法得到弱分类器m,Gm(x):x{1,1}Gm(x):x→{1,−1}

    • 计算Gm(x)Gm(x)在训练数据集上的学习误差率em=P(Gm(x)y)=ni=1wmiI{Gm(xi)yi}em=P(Gm(x)≠y)=∑i=1nwmiI{Gm(xi)≠yi}

    • 计算弱学习器的权重系数αm=12ln1ememαm=12ln1−emem

    • 更新样本权重Dm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmexp(αmyiGm(xi)),i=1,2,...,nDm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmexp(−αmyiGm(xi)),i=1,2,...,n

      其中ZmZm是归一化因子Zm=ni=1wm,iexp(αmyiGm(xi))Zm=∑i=1nwm,iexp(−αmyiGm(xi)),它使得Dm+1Dm+1成为一个概率分布

  3. 构建T个弱分类器的线性组合f(x)=Tm=1αmGm(x)f(x)=∑m=1TαmGm(x),得到最终的强分类器G(x)=sign(f(x))G(x)=sign(f(x))

对以上步骤的说明如下:

  1. 步骤1,假设训练数据集有均匀的样本权重,即每个样本在若分类器中的作用相等,并保证能够学习出第一个弱分类器

  2. 步骤2,算法反复学习弱分类器,每一轮顺序执行以下操作,也分别对应了问题1—4

    • 使用当前的样本权重DmDm加权的训练数据集训练基本分类器Gm(x)Gm(x),这里的弱分类器理论上可以使用任何分类器,最常用的是CART决策树和神经网络

    • 计算弱分类器Gm(x)Gm(x)在加权训练数据集上的分类误差率em=P(Gm(x)y)=ni=1wmiI{Gm(xi)yi}em=P(Gm(x)≠y)=∑i=1nwmiI{Gm(xi)≠yi}。这表明Gm(x)Gm(x)在加权训练集上的分类误差率是被Gm(x)Gm(x)错误分类的样本的权重之和

    • 计算基本分类器的权重系数αm=12ln1ememαm=12ln1−ememαmαm表示弱分类器Gm(x)Gm(x)在最终强分类器中的重要性。从上式可以看出,当em12em≤12时,αm0αm≥0,并且随着emem的减小αmαm增大。这表明,弱分类器Gm(x)Gm(x)的分类误差率越小,其在最终强分类其中的比重越大。而且必须有em12em≤12否则有αm<0αm<0反而使得分类器Gm(x)Gm(x)在强分类器中起反作用。这也说明在二分类中每一个弱分类器的正确率必须大于0.5,比随机分类要好

    • 更新样本权重为下一轮训练弱分类器做准备

      wm+1,i={wmiZmeαm,Gm(xi)=yiwmiZmeαm,Gm(xi)yiwm+1,i={wmiZme−αm,Gm(xi)=yiwmiZmeαm,Gm(xi)≠yi

      有此可知,被弱分类器Gm(x)Gm(x)正确分类的样本的权重下降了,而被错误分类的样本的权重增加了,因此误分类样本在下一轮的学习中被更加重视了。当然,如果αm<0αm<0的话,正好起到相反的作用。不改变训练数据集,而不断改变训练数据的权值分布,使得训练数据在基本分类器的学习中起到不同的作用,这是Adaboost的一个特点。

  3. 步骤3,加权线性组合训练好的T个弱分类器,弱分类器系数αmαm表示基本分类器Gm(x)Gm(x)的重要性,但是这里αmαm的和并不为1。f(x)f(x)的符号决定实例x的类,f(x)f(x)的绝对值表示分类的确信度。利用基本分类器的加权线性组合构建最终的强分类器是Adaboost的另一个特点。

Adaboost二分类算法的推导过程

Adaboost是多个弱分类器加权线性组合的结果。不改变训练数据集,而不断改变训练数据的权值分布,利用不同的加权数据集训练弱分类器,最后将弱分类器加权线性组合。上一节中的算法步骤中展示具体的计算过程,但是其中的公式仅仅是魔法公式吗?这些公式可以从Adaboost的模型、目标损失函数和学习算法中推导出来。

Adaboost算法是模型为加法模型,目标损失函数是指数函数,学习算法为前向分步算法时的二分类学习方法。

  1. 加法模型:f(x)=Tm=1αmGm(x)f(x)=∑m=1TαmGm(x),最终的强分类器是若干个弱分类器的线性加权平均得到的
  2. 指数损失函数:标准形式为L(y,f(x))=exp(yf(x))L(y,f(x))=exp(−yf(x))
  3. 前向分步算法:求解优化问题的思想是,因为学习的是加法模型,如果能够从前向后,每一步只学习一个弱分类器和它的系数,逐步逼近优化目标函数,那么就可以简化优化的复杂度

将以上的模型,目标损失函数和学习算法结合起来,Adaboost算法的推到过程如下:

前向分步算法学习的是加法模型,最终的强分类器是若干个弱分类器的线性加权平均得到的,最终的分类器是

f(x)=m=1TαmGm(x)f(x)=∑m=1TαmGm(x)

其中Gm(x)Gm(x)是弱分类器,αmαm是弱分类器的系数。根据前向分步算法的思想,逐一学习弱分类器Gm(x),m=1,2,...,TGm(x),m=1,2,...,T。假设经过m-1轮的学习,前m-1个弱分类器及其系数已经得到,而且有fm1(x)=m1i=1αiGi(x)fm−1(x)=∑i=1m−1αiGi(x),在第m轮迭代中有

fm(x)=i=1mαiGi(x)=fm1(x)+αmGm(x)fm(x)=∑i=1mαiGi(x)=fm−1(x)+αmGm(x)

我们的目标就是根据前行分步算法得到最优的αmαmGm(x)Gm(x),使得fm(x)fm(x)在训练数据集上的指数损失最小,即目标损失函数为

minα,Gi=1nexp(yifm(xi))minα,Gi=1nexp(yi(fm1(xi)+αmGm(xi)))minα,Gi=1nexp(yifm1(x))exp(yiαmGm(xi))minα,Gi=1nw¯miexp(yiαmGm(xi))(1)minα,G∑i=1nexp(−yifm(xi))⇒minα,G∑i=1nexp(−yi(fm−1(xi)+αmGm(xi)))⇒minα,G∑i=1nexp(−yifm−1(x))exp(−yiαmGm(xi))⇒minα,G∑i=1nw¯miexp(−yiαmGm(xi))−−−−−−−(1)

其中w¯mi=exp(yifm1(x))w¯mi=exp(−yifm−1(x)),因为w¯miw¯miα,Gα,G无关,所以和目标函数 的最小化也无关,但是和fm1(x)fm−1(x)有关,随着每一次的迭代而改变,可以看做是样本的权重,

现在的目标是使得上面的目标函数最小化,分为两步:

  1. 固定αmαm,求Gm(x)Gm∗(x):由于Gm(xi){1,1}yi{1,1}Gm(xi)∈{1,−1},yi∈{1,−1},对任意的αm>0αm>0,(1)式可以写作

    ===i=1nw¯miexp(yiαmGm(xi))yi=Gm(xi)w¯mieαm+yiGm(xi)w¯mieαmw¯mieαmI{yi=Gm(xi)}+w¯mieαmI{yiGm(xi)}(eαmeαm)i=1nw¯mi{yiGm(xi)}+eαm(2)∑i=1nw¯miexp(−yiαmGm(xi))=∑yi=Gm(xi)w¯mie−αm+∑yi≠Gm(xi)w¯mieαm=∑w¯mie−αmI{yi=Gm(xi)}+∑w¯mieαmI{yi≠Gm(xi)}=(eαm−e−αm)∑i=1nw¯mi{yi≠Gm(xi)}+e−αm−−−−−−−(2)

    所以

    Gm(x)=argminGi=1nw¯mi{yiGm(xi)}Gm∗(x)=argminG∑i=1nw¯mi{yi≠Gm(xi)}
    —–(3)

    这里的Gm(x)Gm(x)是adaboost算法中第m个弱分类器,因为它是第m轮前向分步算法中指使数目标函数最小的分类器。

  2. 固定Gm(x)Gm(x),求αmαm∗:将式(2)对αmαm求导,得到

    (eαm+eαm)i=1nw¯mi{yiGm(xi)}eαm=0(eαm+e−αm)∑i=1nw¯mi{yi≠Gm(xi)}−e−αm=0

    得到

    αm=12ln1ememαm∗=12ln1−emem
    —–(4)

    其中

    em=i=1nw¯mi{yiGm(xi)}em=∑i=1nw¯mi{yi≠Gm(xi)}
    ——(5)

    这里emem就是第m个弱分类器的学习误差率,αmαm就是第m个弱分类器的权重系数,和之前算法步骤中的一致

指数目标函数优化之后,得到fm(x)=fm1(x)+αmGm(x)fm(x)=fm−1(x)+αmGm(x),和w¯mi=exp(yifm1(xi))w¯mi=exp(−yifm−1(xi))αmGm(x)αm,Gm(x)分别如式(4)(3)所示,所以可得

w¯m+1,i=exp(yifm(xi))=exp(yi(fm1(x)+αmGm(x)))=exp(yifm1(xi))exp(yiαmGm(x))=w¯m,iexp(yiαmGm(x))w¯m+1,i=exp(−yifm(xi))=exp(−yi(fm−1(x)+αmGm(x)))=exp(−yifm−1(xi))exp(−yiαmGm(x))=w¯m,iexp(−yiαmGm(x))

这和Adaboost步骤2中的权值更新只相差一个归一化系数。其实这里的w¯miw¯mi有具体的定义,和真正的样本权重更新公式一致,而且在之前的公式中,充当的也是样本权重的作用,所以认为是样本权重。

以上是Adaboost分类算法的流程和推导过程,从流程上可以很直接的看出Adaboost是集成学习,将一些弱学习器串联学习,集成强学习器,其中的权重更新是Adaboost的一个特点,看似是魔法函数,但是从推导过程中可以看出,Adaboost是有严谨的模型、损失函数和学习算法的。Adaboost算法是模型为加法模型,目标损失函数是指数函数,学习算法为前向分步算法时的二分类学习方法。

Adaboost多分类

原始的Adaboost算法是针对二分类问题的,多分类问题采用的也是将其分解为多个二分类问题。而SAMMA和SAMMA.R算法不采用这种思路,只是二分类的推广,也是加法模型,指数损失函数和前向分步算法,而且每个弱分类器的正确率只要大于0.5即可。具体参考文献[1]。

SAMMA算法流程:

假设训练集是T={(x1,y1),(x2,y2),...,(xn,yn)}T={(x1,y1),(x2,y2),...,(xn,yn)},训练集在第k个弱学习器上的样本权重是[wk1,wk2,...,wkn],w1i=1n,i=1,2,...,n[wk1,wk2,...,wkn],w1i=1n,i=1,2,...,n,即第一个弱分类器的样本权重是自定义的,yi{1,2,...,K}yi∈{1,2,...,K},K是类别个数

输入:训练数据集,弱学习算法和弱学习器个数T

输出:最终的强分类器f(x)f(x)

  1. 初始化样本权重D1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,nD1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,n

  2. m=1,2,...,Tm=1,2,...,T

    • 使用具有样本权重DmDm的训练数据和弱学习器算法得到弱分类器m,Gm(x):x{1,2,...,K}Gm(x):x→{1,2,...,K}

    • 计算Gm(x)Gm(x)在训练数据集上的学习误差率em=P(Gm(x)y)=ni=1wmiI{Gm(xi)yi}em=P(Gm(x)≠y)=∑i=1nwmiI{Gm(xi)≠yi}

    • 计算弱学习器的权重系数αm=12ln1emem+ln(K1)αm=12ln1−emem+ln(K−1)

    • 更新样本权重Dm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmexp(αmyiGm(xi)),i=1,2,...,nDm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmexp(−αmyiGm(xi)),i=1,2,...,n

      其中ZmZm是归一化因子Zm=ni=1wm,iexp(αmyiGm(xi))Zm=∑i=1nwm,iexp(−αmyiGm(xi)),它使得Dm+1Dm+1成为一个概率分布

  3. 构建T个弱分类器的线性组合f(x)=Tm=1αmGm(x)f(x)=∑m=1TαmGm(x),得到最终的强分类器G(x)=argmaxkTm=1αmI{Gm(x)=k}G(x)=argmaxk∑m=1TαmI{Gm(x)=k}

从中可以看出。SAMMA算法和Adaboost算法唯一的不同是步骤2中的第3步,计算弱学习器权重系数。最后的决策函数是一致的。

Adaboost回归

Adaboost的回归算法有很多,这里是R2算法。具体参考文献[2]

假设训练集是T={(x1,y1),(x2,y2),...,(xn,yn)}T={(x1,y1),(x2,y2),...,(xn,yn)}

输入:训练数据集,弱学习算法和弱学习器个数T

输出:最终的强学习器G(x)G(x)

  1. 初始化样本权重D1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,nD1=[w11,w12,...,w1n],w1i=1n,i=1,2,...,n

  2. m=1,2,...,Tm=1,2,...,T

    • 使用具有样本权重DmDm的训练数据和弱学习器算法得到弱学习器m,Gm(x)Gm(x)

    • 计算弱学习器在训练集上的最大误差Em=max|yiGm(xi)|,i=1,2,...,nEm=max|yi−Gm(xi)|,i=1,2,...,n

    • 计算每个样本的相对误差:

      如果是线性误差:emi=|yiGm(xi)|Ememi=|yi−Gm(xi)|Em

      如果是平方误差:emi=|yiGm(xi)|2Ememi=|yi−Gm(xi)|2Em

      如果是指数误差:emi=1exp(yi+Gm(xi)Em)emi=1−exp(−yi+Gm(xi)Em)

    • 利用每个样本的相对误差,计算回归误差率em=ni=1wmiemiem=∑i=1nwmiemi

    • 计算弱学习器的权重系数αm=em1emαm=em1−em

    • 更新样本权重Dm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmα1emm,i=1,2,...,nDm+1=[wm+1,1,wm+1,2,...,wm+1,n],wm+1,i=wm,iZmαm1−em,i=1,2,...,n

      其中ZmZm是归一化因子Zm=ni=1wm,iα1emmZm=∑i=1nwm,iαm1−em,它使得Dm+1Dm+1成为一个概率分布

  3. 构建T个弱学习器的线性组合f(x)=Tm=1(ln1αm)Gm(x)f(x)=∑m=1T(ln1αm)Gm(x)得到最终的强回归

Adaboost之sklearn

Adaboost的主要优点有:

  1. Adaboost作为分类器时,分类精度很高
  2. 在Adaboost的框架下,可以使用各种回归分类模型来构建弱学习器,非常灵活。
  3. 作为简单的二元分类器时,构造简单,结果可理解。
  4. 不容易发生过拟合

Adaboost的主要缺点有:

 对异常样本敏感,异常样本在迭代中可能会获得较高的权重,影响最终的强学习器的预测准确性。

scikit-learn中Adaboost类库比较直接,就是AdaBoostClassifier和AdaBoostRegressor两个,从名字就可以看出AdaBoostClassifier用于分类,AdaBoostRegressor用于回归。

AdaBoostClassifier使用了两种Adaboost分类算法的实现,SAMME和SAMME.R。而AdaBoostRegressor则使用了我们原理篇里讲到的Adaboost回归算法的实现,即Adaboost.R2。

当我们对Adaboost调参时,主要要对两部分内容进行调参,第一部分是对我们的Adaboost的框架进行调参, 第二部分是对我们选择的弱分类器进行调参。两者相辅相成。下面就对Adaboost的两个类:AdaBoostClassifier和AdaBoostRegressor从这两部分做一个介绍。

框架参数

参数 AdaBoostClassifier AdaBoostRegressor
base_estimator 弱分类器。理论上可以使用任何分类器,一般使用决策树CART和神经网络MLP,默认是决策树,即DecisionTreeClassifier,分类器需要支持样本权重。另外,如果选择的算法是SAMME.R,则弱分类器需要支持概率预测,即学习器预测的方法除了predict还有predict_proba 弱回归器。理论上可以使用任何回归方法,一般使用决策树CART和神经网络MLP,默认是决策树,即DecisionTreeRegressor,回归其需要支持样本权重。
algorithm 这个参数只有AdaBoostClassifier有。主要原因是sklearn实现了两种分类算法,SAMME和SAMME.R。默认使用SAMME.R,需要base_estimator中弱分类器支持概率预测。  
loss   这个参数只有AdaBoostRegressor有。如上一节所示,有三种损失函数可选,’linear’,’square’和’exponential’
n_estimators 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数
learning_rate 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1

弱分类器参数:使用不同的弱学习器,需要不同的若学习其参数,可以参考各个学习器的参数设置,这里不再详述。

函数

函数 AdaBoostClassifier AdaBoostRegressor
fit(X,y[,sample_weight]) 根据训练数据集X和训练标签y训练adaboost分类模型 根据训练数据集X和目标值y训练adaboost回归模型
decision_function(X) 计算数据集X的决策函数sumTm=1αmGm(x)summ=1TαmGm(x)
predict(X) 预测数据集X的类别标签 预测数据集X的目标值
predict_log_proba(X) 属于每个类别的岁数概率
predict_proba(X) 属于每个类别的概率
score(X,y[,sample_weights]) 根据给定的数据集X和其对应的标签计算分类正确率 计算预测目标和和真实值y的平方误差

属性

属性 AdaBoostClassifier AdaBoostRegressor
estimators_ 每一个弱分类器,包括他们的参数  
classes_ 训练样本的类别向量
n_classes_ 训练样本的类别个数
estimator_weights_ 每一个弱分类器的权重系数αα组成的向量  
estimator_errors_ 每个弱分类器的分类误差组成的向量  
feature_importances_ 每个特征的重要性  

例子

import numpy as np
import matplotlib.pyplot as plt
from sklearn.ensemble import AdaBoostClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.datasets import make_gaussian_quantiles

#产生随机样本
X1, y1 = make_gaussian_quantiles(cov=2.0,n_samples=500, n_features=2,n_classes=2, random_state=1)
X2, y2 = make_gaussian_quantiles(mean=(3, 3), cov=1.5,n_samples=500, n_features=2, n_classes=2, random_state=1)
#将两组数据合成一组数据
X = np.concatenate((X1, X2))
y = np.concatenate((y1, - y2 + 1))

#训练AdaBoostClassifier,采用网格法验证最佳的参数
#弱分类器是决策树
#bdt=AdaBoostClassifier(DecisionTreeClassifier(),algorithm="SAMME"),n_estimators=100,learning_rate=0.5)
from sklearn.model_selection import GridSearchCV

grid=GridSearchCV(AdaBoostClassifier(DecisionTreeClassifier(),algorithm="SAMME"),
                  param_grid={"n_estimators":[10,100,200,500,1000],"learning_rate":[0.1,0.2,0.4,0.8,1]},cv=4)
grid.fit(X,y)
print("The best parameters are %s with a score of %0.2f"
      % (grid.best_params_, grid.best_score_))
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

boosting之GBDT

梯度提升树的全称是Gradient Boosting Decison Tree, 简称GBDT。Gradient Boosting和Decision Tree是两个独立的概念,因此应该分类来理解。

Gradient Boosting

首先是boosting,很好理解,前面也介绍过,意思是用一些弱学习器的组合来构造一个强学习器,而且各个弱学习器是串联的关系。因此,boosting不是一个具体的算法,而是一种概念。和这个概念相对应的是一次性构造一个强学习器,如SVM,logisticRegressor等。通常,通过线性组合来构造强学习器,即f(x)=G0(x)+α1G1(x)+...+αTGT(x)f(x)=G0(x)+α1G1(x)+...+αTGT(x)

接下来是Gradient Boosting Modeling(GBM),梯度提升模型。已知boosting中需要构造弱学习器,那么如何构造弱学习器呢?GBM就是构造弱学习器的一种方法。同样,它不是一种具体的算法,而是一种概念。在理解GBM之前,先看一个经典的数值优化问题。

minxf(x)minxf(x)
——-(1)

针对这个优化问题,有一个经典的算法是梯度下降,过程大致如下

  1. 给定一个初始点x0x0
  2. i=1,2,...,maxIteri=1,2,...,maxIterxi=xi1+αi1gi1xi=xi−1+αi−1∗gi−1,其中gi1=f(x)x|x=xi1gi−1=−∂f(x)∂x|x=xi−1
  3. 直到|gi1||gi−1|足够小,或者|xixi1||xi−xi−1|足够小,或者达到迭代次数

以上梯度下降可以理解为:整个寻优的过程就是小步快跑的过程,都向函数下降最快的方向走一步。最优点可以表示为x=x0+α1g1+...+αmaxItergmaxIterx∗=x0+α1g1+...+αmaxItergmaxIter,这和boosting中寻找强学习器的形式一致(而且这个形式和感知机优化问题中的对偶形式一样)。Gradient Boosting正是由此启发而来。构造强学习器f(x)f(x)也是一个寻优的过程,只不过我们寻找的不再是一个最优点,而是一个最优的函数。寻找最优的函数通常是通过一个损失函数来定义的,即:

minf(x)i=1nLoss(f(xi),yi)minf(x)∑i=1nLoss(f(xi),yi)
——–(2)

其中Loss(f(xi),yi)Loss(f(xi),yi)是损失函数,是f(xi)f(xi)的函数,表示泛函。形式(2)和形式(1)一致,可以通过梯度下降的方法优化构造弱分类器Gi(x)Gi(x)。每次迭代时,gi=LossG|G=Gi1gi=−∂Loss∂G|G=Gi−1

这里有个小问题,一个函数对函数的求导不好解决,而且通常都无法通过上述公式直接求解。所以,需要采用一个近似的方法,把函数Gi1(x)Gi−1(x)理解成在所有样本上的离散函数值,即:

[Gi1(x1),Gi1(x2),...,Gi1(xn)][Gi−1(x1),Gi−1(x2),...,Gi−1(xn)]

这是一个n维向量,然后计算

gi(xt)=Loss(G(xt),yt)G(xt)|G(xt)=Gi1(xt),t=1,2,...,ngi(xt)=−∂Loss(G(xt),yt)∂G(xt)|G(xt)=Gi−1(xt),t=1,2,...,n

表示损失函数对第i-1个弱学习器的第t个分量的偏导数,是一个函数对向量的求导,得到的是一个n维的梯度向量。

严格来说。gi(xt)gi(xt)只是表示gi(x)gi(x)在有限个点上的值,不足以代表gi(x)gi(x),但是我们可以通过函数拟合的方法从gi(xt),t=1,2,...ngi(xt),t=1,2,...n中构造gi(x)gi(x),这样我们就通过近似的方法得到了函数对函数的导数。

因此根据经典优化问题的梯度下降算法,可以得到GBM的过程如下:

问题:minf(x)ni=1Loss(f(xi),yi)minf(x)∑i=1nLoss(f(xi),yi)

  1. 选择一个起始函数G0(x)G0(x)
  2. 对i=1,2,…,T分别做如下迭代 
    • 计算离散梯度Gi(xt)=Loss(G(xt),yt)G(xt)|G(xt)=Gi1(xt),t=1,2,...,nGi(xt)=−∂Loss(G(xt),yt)∂G(xt)|G(xt)=Gi−1(xt),t=1,2,...,n
    • 对离散梯度Gi(xt),t=1,2,...nGi(xt),t=1,2,...n做函数拟合得到Gi(x)Gi(x)
    • 根据minαiLoss(fi1(x)+αiGi(x))minαiLoss(fi−1(x)+αiGi(x))得到最优的αiαi∗
    • fi(x)=fi(x)+αiGi(x)fi(x)=fi(x)+αiGi(x)
  3. 直到|Gi(x)||Gi(x)|足够小或者达到迭代次数,算法结束

以上便是GBM的过程,其中还有一个问题没有解决,就是第2步第2条,如何对离散梯度Gi(xt),t=1,2,...nGi(xt),t=1,2,...n做函数拟合得到Gi(x)Gi(x)。拟合的方法有很多种,最常用的是决策树Decision Tree,用Decision Tree拟合的话,就得到了GBDT。当然也可以采用其他的拟合方法XYZ,那么得到的就是GBXYZ了。

Decision Tree

决策树的主要算法有ID3,C4.5和CART,分为分类树和回归树,其中只有CART回归树可以解决回归的问题。在GBDT中需要用决策树拟合数据,所以需要的是回归树,而不是分类树,即使在分类问题中。所以下面着重回忆CART回归树。

CART回归树只要有两个方面,建立树和预测。

  1. 建立回归树:对数据集,寻找最优的特征A和特征上的最优划分值s

    minA,s[minc1xiD1(A,s)(yic1)2+minc2xiD2(A,s)(yic2)2]minA,s[minc1∑xi∈D1(A,s)(yi−c1)2+minc2∑xi∈D2(A,s)(yi−c2)2]

    其中C1是D1的目标均值,C2是D2的目标均值。遍历特征和划分值,根据上式,计算均方误差,选择最好的特征A和划分值s,划分数据为D1和D2。回归树是一颗二叉树。

  2. 预测目标值:对数据xx,利用建立好的回归树得到的预测值是f(x)=Ji=1ciI{xDi}f(x)=∑i=1JciI{x∈Di}。即x的预测值是其所属区域的目标均值C。

那么如何用回归树拟合Gi(xt),t=1,2,...,nGi(xt),t=1,2,...,n呢?数据集和每个数据对应的Gi(xt)Gi(xt)已知,相当给定了一个回归问题,然后选定最佳的特征和划分值构造回归树,回归树中的叶子节点分别为D1,D2,...,DJD1,D2,...,DJ,对应区域的均方值是c1,c2,...,cJc1,c2,...,cJ,所以拟合函数为Gi(x)=Jt=1ct{xDt}Gi(x)=∑t=1Jct{x∈Dt}

这里有一个问题需要注意,Gi(x)Gi(x)相当于boosting中的弱学习器,如果过拟合,必定会造成强学习器的过拟合,所以这里的回归树不能过拟合。

GBDT的一些理解

GBDT可以分为GB和DT两个独立的部分,下面给出GBDT的流程,对于分类和回归的算法框架是一样的,只是目标函数和回归树构造的细节不同。

问题:minf(x)ni=1Loss(f(xi),yi)minf(x)∑i=1nLoss(f(xi),yi)

  1. 初始化弱学习器G0(x)=argminni=1Loss(yi,c)G0(x)=argmin∑i=1nLoss(yi,c)
  2. 对i=1,2,…,T分别做如下迭代 
    • 计算离散梯度Gi(xt)=Loss(G(xt),yt)G(xt)|G(xt)=Gi1(xt),t=1,2,...,nGi(xt)=−∂Loss(G(xt),yt)∂G(xt)|G(xt)=Gi−1(xt),t=1,2,...,n
    • 利用回归树对(xt,Gi(xt))(xt,Gi(xt))拟合得到Gi(x)=Jj=1cij{xDij}Gi(x)=∑j=1Jcij{x∈Dij}
    • 根据minαiLoss(fi1(x)+αiGi(x))minαiLoss(fi−1(x)+αiGi(x))得到最优的αiαi
    • fi(x)=fi(x)+αiGi(x)fi(x)=fi(x)+αiGi(x)
  3. 直到|Gi(x)||Gi(x)|足够小或者达到迭代次数,算法结束,得到的强学习器为f(x)=Ti=1αiJj=1cijI{xDij}f(x)=∑i=1Tαi∑j=1JcijI{x∈Dij}

上面的算法中有一个地方没有明确,就是第2步第1条中的损失函数。常用的损失函数有:

  1. 回归:

    • 平方差损失Loss(f(x),y)=12(yf(x))2Loss(f(x),y)=12(y−f(x))2,对应的负梯度为yf(x)y−f(x)

    • 绝对损失Loss(f(x),y)=|yf(x)|Loss(f(x),y)=|y−f(x)|,对应的负梯度为sign(yf(x))sign(y−f(x))

    • Huber损失,是平方差损失和绝对损失的折中,对于原理中心的异常点,采用绝对损失,而中心店附近的点采用平方差损失。这个界限一般用分位数点度量。

      Loss(f(x),y)={12(yf(x))2δ(|yf(x)|δ2)|yf(x)|δ|yf(x)|>δLoss(f(x),y)={12(y−f(x))2|y−f(x)|≤δδ(|y−f(x)|−δ2)|y−f(x)|>δ

      对应的负梯度为:

      {yf(x)δsign(yf(x))|yf(x)|δ|yf(x)|>δ{y−f(x)|y−f(x)|≤δδsign(y−f(x))|y−f(x)|>δ

    • 分位数损失,表达式为

      Loss(f(x),y)=yf(x)θ|yf(x)|+y<f(x)(1θ)|yf(x)|Loss(f(x),y)=∑y≥f(x)θ|y−f(x)|+∑y<f(x)(1−θ)|y−f(x)|

      对应的负梯度为:

      {θθ1yf(x)y<f(x){θy≥f(x)θ−1y<f(x)

      Huber损失和分位数损失主要是为了健壮回归,也就是减少异常点对损失函数的影响。

  2. 分类

    • 指数损失函数:Loss(f(x),y)=exp(yf(x))Loss(f(x),y)=exp(−yf(x)),对应的负梯度为yexp(yf(x))y∗exp(−yf(x))

    • 对数损失函数,分为二元分类和多元分类

      二元分类:Loss(f(x),y)=log(1+exp(yf(x)))Loss(f(x),y)=log(1+exp(−yf(x))),对应的负梯度为y1+exp(yf(x))y1+exp(yf(x))

      多元分类:Loss(f(x),y)=Kk=1yklogpk(x)Loss(f(x),y)=−∑k=1Kyklogpk(x),其中如果f(x)f(x)属于第k类,则yk=1,pk(x)=exp(fk(x))/Kl=1exp(fl(x))yk=1,pk(x)=exp(fk(x))/∑l=1Kexp(fl(x))。对应的负梯度为yilpl(xi)yil−pl(xi),表示样本i对应类别l的负梯度,公有K个负梯度向量,每个向量是n维的。

对于回归和分类,分别拿出一个损失函数讨论,而且这两个损失函数是最特别的两个。

  1. 平方差损失函数:按照GBDT算法中的第二步,首先计算每个样本关于损失函数的负梯度,得到git=ytfi(xt)git=yt−fi(xt),这个形式刚好是目标值和前i次迭代得到的强分类器的差值。然后用回归树拟合git,t=1,2,...,ngit,t=1,2,...,n得到的Gi(x)Gi(x)可以说是对残差的拟合。通常情况下说GBDT是用弱分类器拟合残差,这个说法不准确,只有当损失函数是平方差损失时,才可以说弱分类器是岁残差的拟合。而损失函数时其他形式时,只能说梯度是残差的近似。

  2. 指数损失函数:当GBDT的损失函数为指数损失函数时,和adaboost的弱学习器为回归树时是等价的(?为什么)

    (在第i轮迭代中,指数损失函数的表达式为:

    Loss(fi1(x),y)=exp(yfi1(x))Loss(fi−1(x),y)=exp(−yfi−1(x))

    对每个样本求负倒数的结果是

    Loss(fi1(xt))fi1(xt)=ytexp(ytfi1(xt))−∂Loss(fi−1(xt))∂fi−1(xt)=yt∗exp(−ytfi−1(xt))
    —-(4)

    这时需要用回归树拟合(xt,ytexp(ytfi1(xt)))(xt,yt∗exp(−ytfi−1(xt))),拟合得到弱分类器Gi(x)Gi(x),根据minαiLoss(fi(x)+αiGi(x))minαiLoss(fi(x)+αiGi(x))得到最优的αiαifi(x)=fi1+αiGi(x)fi(x)=fi−1+αiGi(x),此时新的损失函数为

    Loss(fi(x),y)=exp(yexp(yfi1(x))fi(x))Loss(fi(x),y)=exp(−y∗exp(−yfi−1(x))∗fi(x))

    在adaboost中)

另外adaboost和GBDT有什么关系呢?我们知道,adaboost是加法模型,使用前向分步算法求解模型的最优解,损失函数是指数函数。而GBDT是也是加法模型,但是求解是采用的方法是梯度下降。对于GDBT使用平方差损失函数和指数损失函数,用前向分步算法也可以实现GBDT。当使用平方差损失函数时,拟合残差即可;当使用指数损失函数时,拟合带权重的样本即可。但是当损失函数是其他形式时,便不能将前向分步算法再扩展了。相比而言,梯度GBM每步只要计算损失函数对于样本的导数即可,并在平方差损失的基础上拟合梯度。虽然梯度的计算依赖于损失函数,但这并没有太大的问题,只要损失函数是连续可微,梯度便可以计算。至于拟合这个子问题,是在平方差损失这个前提进行的,也就是说不管GBM模型的损失函数是什么,拟合子问题的损失函数都是平方差损失函数,也即回归树的损失函数是平方差损失函数。

虽然前向分步算法和梯度下降从形式上是一样的,但是本质是不一样的。GBM模型可以适用更多的损失函数。

最后,为什么GBDT受欢迎呢?可以从两方面分析,一方面是GBDT算法本身,一方面是弱学习器回归树。

  1. GBDT可以适应更多的损失函数,可以选择鲁棒性较高的损失函数,如Huber

  2. 可以处理各种数据,离散和连续的

  3. 在相对较少的调参下,准确率较高。这个是对于SVM来说的

  4. GBDT不容易过拟合

  5. Decision Tree 可以很好的处理 missing feature,这是他的天然特性,因为决策树的每个节点只依赖一个 feature,如果某个 feature 不存在,这颗树依然可以拿来做决策,只是少一些路径。像逻辑回归,SVM 就没这个好处。

  6. Decision Tree 可以很好的处理各种类型的 feature,也是天然特性,很好理解,同样逻辑回归和 SVM 没这样的天然特性。
  7. 对特征空间的 outlier 有鲁棒性,因为每个节点都是 x < T 的形式,至于大多少,小多少没有区别,outlier 不会有什么大的影响,同样逻辑回归和 SVM 没有这样的天然特性。
  8. 如果有不相关的 feature,没什么干扰,如果数据中有不相关的 feature,顶多这个 feature 不出现在树的节点里。逻辑回归和 SVM 没有这样的天然特性(但是有相应的补救措施,比如逻辑回归里的 L1 正则化)。
  9. 数据规模影响不大,因为我们对弱分类器的要求不高,作为弱分类器的决策树的深 度一般设的比较小,即使是大数据量,也可以方便处理。像 SVM 这种数据规模大的时候训练会比较麻烦。

GBDT的缺点:

由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的SGBT来达到部分并行。

GBDT之sklearn

在sklearn.ensemble中,有GradientBoostingClassifier和GradientBoostingRegressor分别用来分类和回归。两者大部分的参数类型相同。这些参数类似于Adaboost,可以把参数分为两类,第一类是框架参数,第二类是弱学习器的参数。

框架参数

参数 GradientBoostingClassifier GradientBoostingRegressor
loss GBDT中的损失函数,对于分类模型,有对数似然函数”deviance”和指数损失函数”exponential”。默认是”deviance”,对二分类和多分类都有比较好的优化。而”exponential”算法等价于adaboost GBDT中的损失函数,对于回归模型,有均方误差’ls’,绝对损失’lad’,HUber损失’huber’和分位数损失’quantile’。默认是均方误差’ls’。一般来说,如果数据的噪音不多,用默认的‘ls’即可,如果噪音较多,推荐使用健壮性更强的‘huber’。如果需要对训练集进行分段预测的话,选用‘quantile’
n_estimators 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数
learning_rate 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1
init 初始化的弱学习器。默认则用训练集样本做样本的初始化分类。否则用init提供的学习其参数做初始化的分类。一般对数据没有先验知识的话,默认这个参数。 初始化的弱学习器。默认则用训练集样本做样本的初始化回归。否则用init提供的学习其参数做初始化的回归。一般对数据没有先验知识的话,默认这个参数。
subsample 正则化采样,取值为(0,1]。这里的子采样和随机森林中的不一样,不是放回采样。如果取值为1,则用全部的样本训练,如果小于1,则选用一部分样本训练。小于1可以防止过拟合,但也会增加偏差,一般选择[0.5,0.8] 正则化采样,取值为(0,1]。这里的子采样和随机森林中的不一样,不是放回采样。如果取值为1,则用全部的样本训练,如果小于1,则选用一部分样本训练。小于1可以防止过拟合,但也会增加偏差,一般选择[0.5,0.8]
alpha   当使用hube损失和分位数损失的时候,需要制定分位数的值,默认是0.9

弱分类器参数:弱分类器即决策树的参数

参数 GradientBoostingClassifier GradientBoostingRegressor
max_features 划分时考虑的特征个数:可以使用很多类型的值。默认是’None’,表示划分时考虑所有的特征;如果是‘log2’,表示最多log2N个特征;如果是‘sqrt’或‘auto’表示考虑NN个特征;如果是正是,表示考虑特征的个数;如果是浮点数,表示百分比。一般来说,如果特征个数不多,比如小于50,默认即可。如果特征很多,可以灵活使用该参数,控制决策树生成时间。而subsample考虑的样本数 划分时考虑的特征个数:可以使用很多类型的值。默认是’None’,表示划分时考虑所有的特征;如果是‘log2’,表示最多log2N个特征;如果是‘sqrt’或‘auto’表示考虑NN个特征;如果是正是,表示考虑特征的个数;如果是浮点数,表示百分比。一般来说,如果特征个数不多,比如小于50,默认即可。如果特征很多,可以灵活使用该参数,控制决策树生成时间。而subsample考虑的样本数
max_depth 决策树的深度,默认不输入,深度不限制。int类型,表示深度。一般来说,如果数据少或者特征少,可以不输入。如果样本多或者特征多时,参数取决于数据的分布。常用取值10-100 决策树的深度,默认不输入,深度不限制。int类型,表示深度。一般来说,如果数据少或者特征少,可以不输入。如果样本多或者特征多时,参数取决于数据的分布。常用取值10-100
min_samples_split 这个值限制了子树继续划分的条件,如果节点中的样本数小于min_sample_split,则不会继续划分,这个节点将作为叶节点。默认是2.如果样本量不大,默认即可。如果样本量很大,尝试增大这个值 这个值限制了子树继续划分的条件,如果节点中的样本数小于min_sample_split,则不会继续划分,这个节点将作为叶节点。默认是2.如果样本量不大,默认即可。如果样本量很大,尝试增大这个值
min_samples_leaf 这个值限制了叶子结点在剪枝过程中的最少样本数。如果叶子结点中的样本数小于这个值,则和兄弟节点一起被剪枝。 这个值限制了叶子结点在剪枝过程中的最少样本数。如果叶子结点中的样本数小于这个值,则和兄弟节点一起被剪枝。
min_weight_fraction_leaf 这个值限制的叶子结点中所有样本权重之和,如果小于这个值,则会和兄弟节点一起被剪枝。默认是0,不考虑权值。一般来说,如果我们有较多的缺失值或者样本类别不平衡,会在模型中引入样本权重,这是需要注意这个值。 这个值限制的叶子结点中所有样本权重之和,如果小于这个值,则会和兄弟节点一起被剪枝。默认是0,不考虑权值。一般来说,如果我们有较多的缺失值或者样本类别不平衡,会在模型中引入样本权重,这是需要注意这个值。
max_leaf_nodes 通过限制最大叶子数,可以防止过拟合。默认是’None’,不限制叶子结点数。如果特征不多,可以默认,如果特征多的话,可以加以限制,集体通过交叉验证得到 通过限制最大叶子数,可以防止过拟合。默认是’None’,不限制叶子结点数。如果特征不多,可以默认,如果特征多的话,可以加以限制,集体通过交叉验证得到
min_impurity_split 节点划分最小不纯度,限制了决策树的增长,如果节点不纯度小于这个阈值,则该节点不再划分。一般选择默认。 节点划分最小不纯度,限制了决策树的增长,如果节点不纯度小于这个阈值,则该节点不再划分。一般选择默认。

函数

函数 GradientBoostingClassifier GradientBoostingRegressor
fit(X,y[,sample_weight]) 根据训练数据集X和训练标签y训练adaboost分类模型 根据训练数据集X和目标值y训练adaboost回归模型
decision_function(X) 计算数据集X的决策函数sumTm=1αmGm(x)summ=1TαmGm(x)
apply(X) 将强学习器用于X,返回叶节点的索引。输入X,样本数据,输出X-leaves,shape=[n_sample,n_estimator,n_calsses],对于X中的数据x,返回x在每个若学习其中的叶子索引 将强学习器用于X,返回叶节点的索引。输入X,样本数据,输出X-leaves,shape=[n_sample,n_estimator,n_calsses],对于X中的数据x,返回x在每个若学习其中的叶子索引
predict(X) 预测数据集X的类别标签 预测数据集X的目标值
predict_log_proba(X) 属于每个类别的岁数概率
predict_proba(X) 属于每个类别的概率
score(X,y[,sample_weights]) 根据给定的数据集X和其对应的标签计算分类正确率 计算预测目标和和真实值y的平方误差

属性

属性 GradientBoostingClassifier GradientBoostingRegressor
estimators_ 每一个决策树的参数  
oob_improvement_ 相对于前一个决策树回归loss的改善,oob_improvement_是第一个回归树的loss  
train_score_ train_score_[i]是第i次迭代中分类器的偏差  
loss_ 损失函数  
estimator_errors_ 每个弱分类器的分类误差组成的向量  
feature_importances_ 每个特征的重要性  

例子

见GBDTSklearn.py

xgboost

xgboost是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包,比常见的工具包快10倍以上。在数据科学方面,有大量kaggle选手选用它进行数据挖掘比赛,其中包括两个以上kaggle比赛的夺冠方案。在工业界规模方面,xgboost的分布式版本有广泛的可移植性,支持在YARN, MPI, Sungrid Engine等各个平台上面运行,并且保留了单机并行版本的各种优化,使得它可以很好地解决于工业界规模的问题。

这里先不实践,之后学习完集成算法之后进行实践

参考:

http://blog.csdn.net/sb19931201/article/details/52557382

http://blog.csdn.net/ni_guang2010/article/details/53350034

bagging之随机森林

bagging算法相比于boosting算法思想很简单,虽然都是弱学习器的集成,但是各个弱学习器之间是并行的,相关性很小,因此可以在大规模数据上并行计算,这也是bagging算法最大的一个优点。

bagging算法

先看一下bagging算法的流程,然后一步一步解释:

输入:样本集{(x1,y1),(x2,y2),...,(xn,yn)}{(x1,y1),(x2,y2),...,(xn,yn)},学弱习算法和迭代次数T

输出:强学习器f(x)f(x)

  1. 对于m=1,2,...,Tm=1,2,...,T 
    • 对训练集进行第m次随机采样,得到包含n个样本的数据集DmDm
    • 用采样得到的数据集DmDm训练第m个弱学习器Gm(x)Gm(x)
  2. 如果是分类算法,则用多数投票得到最后的强分类器,如果树回归问题,T个弱学习器得到的回归结果进行算数平均得到最后的强学习器。

第一个问题是弱学习器,可以使用任何分类或回归算法,最常用的是神经网络和决策树

第二个问题是随机采样,这也是bagging算法中最重要的一点。随机采样就是从训练集中采集固定个数的样本,但是每采集一个样本后,都将样本放回。也就是之前采集到的样本之后有可能继续被采集到。对于bagging算法来说,一般随机采样得到的数据集中样本的个数和原始训练集中样本的个数一样。这样采集的数据集和训练数据集的个数一样,但内容不一样。我们对训练集进行T次随机采样,得到T个数据集,这T个数据集的大小一样,但是内容不一样。

注意这和GBDT中的子采样subsamples不一样,GBDT中的采样是无放回的。

对于一个样本,在某一次随机采样中,假设需要采集n个样本,则每次被采集到的概率是1/n1/n,不被采集到的概率是11/n1−1/n。n次采样都没有被采集中的概率是(11/n)n(1−1/n)n,当nn→∞时,有(11/n)n1/e0.368(1−1/n)n→1/e≃0.368。也就是说,在bagging的每次随机采样中,大概会有36.8%36.8%的数据没有被采集到。对于这些数据,称之为袋外数据,可以用来检测弱学习器的泛化能力。

由于bagging每次都进行随机采样来训练数据,因此泛化能力很强,可以有效的降低过拟合的风险。但是对于训练数据的准确率会较低一点。

随机森林(RF)

随机森林是bagging的进化版本,它的思想任然是bagging,但是进行的独有的改进。

  1. RF使用CART作为弱学习器
  2. 在使用决策树时,RF对决策树的建立做了改进。对于普通的决策树,我们会在节点上使用所有特征,选择最佳的特征来做节点的划分,但是RF通过随机选择部分特征,假设为s个,然后在这s个随机选择的特征中选择最优的一个特征作为子节点的划分。如果s=m,则RF中的CART决策树和普通的CART决策树没有区别。s月越小,则模型越健壮,但是偏差会增大。一般通过交叉验证来选择合适的s。

先看一下bagging算法的流程,然后一步一步解释:

输入:样本集{(x1,y1),(x2,y2),...,(xn,yn)}{(x1,y1),(x2,y2),...,(xn,yn)},若学习算法和迭代次数T

输出:强学习器f(x)f(x)

  1. 对于m=1,2,...,Tm=1,2,...,T 
    • 对训练集进行第m次随机采样,得到包含n个样本的数据集DmDm
    • 用采样得到的DmDm数据集训练第m个弱学习器Gm(x)Gm(x),在训练模型的时候,在所有特征中随机选择s个特征,在s个随机选择的特征中选择最优的一个特征最为决策树节点划分的依据
  2. 如果是分类算法,则用多数投票得到最后的强分类器,如果树回归问题,T个弱学习器得到的回归结果进行算数平均得到最后的强学习器。

随机森林的推广

  1. extra tree(极端随机树):是RF的一个变种。主要区别有两点:

    • 不进行随机采样,每个CART训练时采用原始数据集
    • 在构建CART决策树时,随机选择s个特征,RF是根据信息增益,基尼系数或均方差等选择最佳的特征以及特征的划分进行节点的再分裂。但是ET是在每个特征中随机决定一个划分值,然后计算每个特征上的信息增益,基尼系数或者均方差,选择最佳的一个。也就是说ET对于特征的划分有更加随机的选择,使得随机森林的随机性更强了。泛化能力也更好了。

    ET在sklearn.ensemble有实现,有ExtraTreeClassifier和ExtraTreeRegrassor

  2. Totally Random Trees Embedding:(以下简称 TRTE)是一种非监督学习的数据转化方法。它将低维的数据集映射到高维,从而让映射到高维的数据更好的运用于分类回归模型。我们知道,在支持向量机中运用了核方法来将低维的数据集映射到高维,此处TRTE提供了另外一种方法。

    TRTE在数据转化的过程也使用了类似于RF的方法,建立T个决策树来拟合数据。当决策树建立完毕以后,数据集里的每个数据在T个决策树中叶子节点的位置也定下来了。比如我们有3颗决策树,每个决策树有5个叶子节点,某个数据特征x划分到第一个决策树的第2个叶子节点,第二个决策树的第3个叶子节点,第三个决策树的第5个叶子节点。则x映射后的特征编码为(0,1,0,0,0, 0,0,1,0,0, 0,0,0,0,1), 有15维的高维特征。这里特征维度之间加上空格是为了强调三颗决策树各自的子编码。

    映射到高维特征后,可以继续使用监督学习的各种分类回归算法了。

  3. Isolation Forest:也称为孤立森林,用于异常值的检测。使用了类似于RF的方法来检测异常值。iForest和RF的区别有以下三点:

    • 在随机采样部分,iForest不需要采集和原始数据集个数一样的样本个数,只需要很少的样本即可。因为我们的目的是异常值检测,只需要部分样本就可以将异常点区别出来了。
    • 对于每一个决策树的建立,iForest随机选择一个特征,对特征随机选择一个划分阈值进行节点的再分裂。
    • iForest的决策树的最大深度一般较小

    在训练完模型之后,如何进行异常值检测呢?我们可以得到T棵决策树,对于测试样本x,计算在每棵决策树上该样本所属叶子结点的深度ht(x)ht(x),从而可以计算出平均深度h(x)h(x)。然后用以下公式计算x是异常点的概率:

    s(x,n)=2h(x)/c(m)s(x,n)=2−h(x)/c(m)

    其中c(n)=2H(n1)(2(n1)/n)c(n)=2H(n−1)−(2(n−1)/n)H(k)=ln(k)+ξH(k)=ln(k)+ξξξ是欧拉常数,其值为0.5772156649,n为样本个数

    s(x,n)s(x,n)越接近1,是异常点的可能性越大。如果所有样本点的s(x,n)s(x,n)都小于0.5,则基本断定数据集正常;如果都在0.5附近,那么数据集不包含明显异常数据。

    iForest在sklearn.ensemble有实现,有IsolationForest方法。

随机森林的小结

RF的算法原理也终于讲完了,作为一个可以高度并行化的算法,RF在大数据上大有可为。 这里也对常规的随机森林算法的优缺点做一个总结。

RF的主要优点有:

  1. 训练可以高度并行化,对于大数据时代的大样本训练速度有优势。个人觉得这是的最主要的优点。
  2. 由于可以随机选择决策树节点划分特征,这样在样本特征维度很高的时候,仍然能高效的训练模型
  3. 在训练后,可以给出各个特征对于输出的重要性
  4. 由于采用了随机采样,训练出的模型的方差小,泛化能力强。
  5. 相对于Boosting系列的Adaboost和GBDT, RF实现比较简单。
  6. 对部分特征缺失不敏感。

RF的主要缺点有:

  1. 在某些噪音比较大的样本集上,RF模型容易陷入过拟合。
  2. 取值划分比较多的特征容易对RF的决策产生更大的影响,从而影响拟合的模型的效果。

随机森林之sklearn

在sklearn.ensemble中,RandomForestClassifier和RandomForestRegressor分别是税及森林的分类和回归。其中的参数也分为两类,框架参数和决策树参数。

框架参数

参数 RandomForestClassifier RandomForestRegressor
n_estimators 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数 弱分类器的个数,太小,容易欠拟合,太大,容易过拟合,默认是50,需要交叉验证选择最佳的个数
learning_rate 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1 学习率vv,相当于损失函数中的正则项,0<v<10<v<1,常和上面的n_estimotors结合使用。太小,需要更多的弱学习器,太大,需要较少的弱学习器。默认是1
oob_score 是否采用袋外样本来评估模型的好坏。默认False,如果设置为True,可以反映模型拟合后的泛化能力。 是否采用袋外样本来评估模型的好坏。默认False,如果设置为True,可以反映模型拟合后的泛化能力。
criterion 即CART节点做划分时对特征的评价标准。回归的损失函数是gini和entropy。默认是gini 即CART节点做划分时对特征的评价标准。有均方差mse和绝对值差mae,默认是mse

随机森林的框架参数比较少,最主要的还是n_estimators,弱分类器的个数。

弱分类器参数:即CART的参数

参数 GradientBoostingClassifier GradientBoostingRegressor
max_features 划分时考虑的特征个数:可以使用很多类型的值。默认是’None’,表示划分时考虑所有的特征;如果是‘log2’,表示最多log2N个特征;如果是‘sqrt’或‘auto’表示考虑NN个特征;如果是正是,表示考虑特征的个数;如果是浮点数,表示百分比。一般来说,如果特征个数不多,比如小于50,默认即可。如果特征很多,可以灵活使用该参数,控制决策树生成时间。而subsample考虑的样本数 划分时考虑的特征个数:可以使用很多类型的值。默认是’None’,表示划分时考虑所有的特征;如果是‘log2’,表示最多log2N个特征;如果是‘sqrt’或‘auto’表示考虑NN个特征;如果是正是,表示考虑特征的个数;如果是浮点数,表示百分比。一般来说,如果特征个数不多,比如小于50,默认即可。如果特征很多,可以灵活使用该参数,控制决策树生成时间。而subsample考虑的样本数
max_depth 决策树的深度,默认不输入,深度不限制。int类型,表示深度。一般来说,如果数据少或者特征少,可以不输入。如果样本多或者特征多时,参数取决于数据的分布。常用取值10-100 决策树的深度,默认不输入,深度不限制。int类型,表示深度。一般来说,如果数据少或者特征少,可以不输入。如果样本多或者特征多时,参数取决于数据的分布。常用取值10-100
min_samples_split 这个值限制了子树继续划分的条件,如果节点中的样本数小于min_sample_split,则不会继续划分,这个节点将作为叶节点。默认是2.如果样本量不大,默认即可。如果样本量很大,尝试增大这个值 这个值限制了子树继续划分的条件,如果节点中的样本数小于min_sample_split,则不会继续划分,这个节点将作为叶节点。默认是2.如果样本量不大,默认即可。如果样本量很大,尝试增大这个值
min_samples_leaf 这个值限制了叶子结点在剪枝过程中的最少样本数。如果叶子结点中的样本数小于这个值,则和兄弟节点一起被剪枝。 这个值限制了叶子结点在剪枝过程中的最少样本数。如果叶子结点中的样本数小于这个值,则和兄弟节点一起被剪枝。
min_weight_fraction_leaf 这个值限制的叶子结点中所有样本权重之和,如果小于这个值,则会和兄弟节点一起被剪枝。默认是0,不考虑权值。一般来说,如果我们有较多的缺失值或者样本类别不平衡,会在模型中引入样本权重,这是需要注意这个值。 这个值限制的叶子结点中所有样本权重之和,如果小于这个值,则会和兄弟节点一起被剪枝。默认是0,不考虑权值。一般来说,如果我们有较多的缺失值或者样本类别不平衡,会在模型中引入样本权重,这是需要注意这个值。
max_leaf_nodes 通过限制最大叶子数,可以防止过拟合。默认是’None’,不限制叶子结点数。如果特征不多,可以默认,如果特征多的话,可以加以限制,集体通过交叉验证得到 通过限制最大叶子数,可以防止过拟合。默认是’None’,不限制叶子结点数。如果特征不多,可以默认,如果特征多的话,可以加以限制,集体通过交叉验证得到
min_impurity_split 节点划分最小不纯度,限制了决策树的增长,如果节点不纯度小于这个阈值,则该节点不再划分。一般选择默认。 节点划分最小不纯度,限制了决策树的增长,如果节点不纯度小于这个阈值,则该节点不再划分。一般选择默认。

上面决策树参数中最重要的包括最大特征数max_features, 最大深度max_depth, 内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf。

函数

函数 AdaBoostClassifier AdaBoostRegressor
fit(X,y[,sample_weight]) 根据训练数据集X和训练标签y训练adaboost分类模型 根据训练数据集X和目标值y训练adaboost回归模型
decision_path(X) 计算样本的决策路径,返回节点指示矩阵,shape=[n_samples,n_nodes],,矩阵中的非零元素表示样本通过该节点。 计算样本的决策路径,返回节点指示矩阵,shape=[n_samples,n_nodes],,矩阵中的非零元素表示样本通过该节点。
apply(X) 将强学习器用于X,返回叶节点的索引。输入X,样本数据,输出X-leaves,shape=[n_sample,n_estimator,n_calsses],对于X中的数据x,返回x在每个若学习其中的叶子索引 将强学习器用于X,返回叶节点的索引。输入X,样本数据,输出X-leaves,shape=[n_sample,n_estimator,n_calsses],对于X中的数据x,返回x在每个若学习其中的叶子索引
predict(X) 预测数据集X的类别标签 预测数据集X的目标值
predict_log_proba(X) 属于每个类别的岁数概率
predict_proba(X) 属于每个类别的概率
score(X,y[,sample_weights]) 根据给定的数据集X和其对应的标签计算分类正确率 计算预测目标和和真实值y的平方误差

属性

属性 AdaBoostClassifier AdaBoostRegressor
estimators_ 返回决策树的列表  
classes_ 训练样本的类别向量
n_classes_ 训练样本的类别个数
n_features_ 参与建模的特征个数  
n_outputs_    
oob_score_ 使用袋外数据得到的模型的准确率,参数oob_score设置为True  
oob_decision_function_ 用模型训练的决策函数计算袋外数据的预测值。当n_estimator较小时,有些样本从来都不是袋外数据,结果可能会包含NAN  
feature_importances_ 每个特征的重要性  

例子

参见randomForestSklearn.py

sklearn.ensemble整体调参总结

在sklearn.ensemble库中,我们可以找到Random Forest分类和回归的实现:RandomForestClassifier和RandomForestRegression,GBDT分类和回归的实现:GradientBoostingClassifier和GradientBoostingRegression。有了这些模型后,立马上手操练起来?少侠请留步!且听我说一说,使用这些模型时常遇到的问题:

  • 明明模型调教得很好了,可是效果离我的想象总有些偏差?——模型训练的第一步就是要定好目标,往错误的方向走太多也是后退。
  • 凭直觉调了某个参数,可是居然没有任何作用,有时甚至起到反作用?——定好目标后,接下来就是要确定哪些参数是影响目标的,其对目标是正影响还是负影响,影响的大小。
  • 感觉训练结束遥遥无期,sklearn只是个在小数据上的玩具?——虽然sklearn并不是基于分布式计算环境而设计的,但我们还是可以通过某些策略提高训练的效率。
  • 模型开始训练了,但是训练到哪一步了呢?——饱暖思淫欲啊,目标,性能和效率都得了满足后,我们有时还需要有别的追求,例如训练过程的输出,袋外得分计算等等。

参数总结

通过总结这些常见的问题,我们可以把模型的参数分为4类:目标类、性能类、效率类和附加类。下表详细地展示了4个模型参数的意义:

参数 类型 RandomForestClassifier RandomForestRegressor GradientBoostingClassifier GradientBoostingRegressor
loss 目标     损失函数 ●exponential:模型等同AdaBoost ★ deviance:和Logistic Regression的损失函数一致 损失函数,★ls:均方误差 ●lad:绝对损失 ●huber : Huber损失●quantile:分位数损失 一般来说,如果数据的噪音不多,用默认的‘ls’即可,如果噪音较多,推荐使用健壮性更强的‘huber’。如果需要对训练集进行分段预测的话,选用‘quantile’
alpha 目标       损失函数为huber或quantile的时,alpha为损失函数中的参数
class_weight 目标 类别的权值      
n_estimators [1] 性能 子模型的数量● int:个数★ 10:默认值 子模型的数量● int:个数★ 10:默认值 子模型的数量● int:个数★ 100:默认值 子模型的数量● int:个数★ 100:默认值
learning_rate 性能     学习率(缩减) 学习率(缩减)
criterion 性能 判断节点是否继续分裂采用的计算方法● entropy★ gini 判断节点是否继续分裂采用的计算方法★ mse ●mae    
max_features 性能 节点分裂时参与判断的最大特征数● int:个数● float:占所有特征的百分比★ auto:所有特征数的开方● sqrt:所有特征数的开方● log2:所有特征数的log2值● None:等于所有特征数 节点分裂时参与判断的最大特征数● int:个数● float:占所有特征的百分比★ auto:所有特征数的开方● sqrt:所有特征数的开方● log2:所有特征数的log2值● None:等于所有特征数 节点分裂时参与判断的最大特征数● int:个数● float:占所有特征的百分比● auto:所有特征数的开方● sqrt:所有特征数的开方● log2:所有特征数的log2值★ None:等于所有特征数 节点分裂时参与判断的最大特征数● int:个数● float:占所有特征的百分比● auto:所有特征数的开方● sqrt:所有特征数的开方● log2:所有特征数的log2值★ None:等于所有特征数
max_depth[2] 性能 最大深度,如果max_leaf_nodes参数指定,则忽略● int:深度★ None:树会生长到所有叶子都分到一个类,或者某节点所代表的样本数已小于min_samples_split 最大深度,如果max_leaf_nodes参数指定,则忽略● int:深度★ None:树会生长到所有叶子都分到一个类,或者某节点所代表的样本数已小于min_samples_split 最大深度,如果max_leaf_nodes参数指定,则忽略● int:深度★ 3:默认值 最大深度,如果max_leaf_nodes参数指定,则忽略● int:深度★ 3:默认值
min_samples_split 性能 限制了节点继续划分的条件,如果节点中的样本个数小于这个值,该节点作为叶节点。● int:样本数★ 2:默认值 限制了节点继续划分的条件,如果节点中的样本个数小于这个值,该节点作为叶节点。● int:样本数★ 2:默认值 限制了节点继续划分的条件,如果节点中的样本个数小于这个值,该节点作为叶节点。● int:样本数★ 2:默认值 限制了节点继续划分的条件,如果节点中的样本个数小于这个值,该节点作为叶节点。● int:样本数★ 2:默认值
min_samples_leaf 性能 叶节点最小样本数,限制了剪枝过程中叶节点的个数。如果小于这个值,则和左右兄弟节点一起被剪枝 ● int:样本数★ 1:默认值 叶节点最小样本数,限制了剪枝过程中叶节点的个数。如果小于这个值,则和左右兄弟节点一起被剪枝 ● int:样本数★ 1:默认值 叶节点最小样本数,限制了剪枝过程中叶节点的个数。如果小于这个值,则和左右兄弟节点一起被剪枝 ● int:样本数★ 1:默认值 叶节点最小样本数,限制了剪枝过程中叶节点的个数。如果小于这个值,则和左右兄弟节点一起被剪枝 ● int:样本数★ 1:默认值
min_weight_fraction_leaf 性能 叶节点最小样本权重总值,如果叶节点的权重值小于这个值,则和兄弟节点一起被剪枝 ● float:权重总值★ 0:默认值 叶节点最小样本权重总值,如果叶节点的权重值小于这个值,则和兄弟节点一起被剪枝 ● float:权重总值★ 0:默认值 叶节点最小样本权重总值,如果叶节点的权重值小于这个值,则和兄弟节点一起被剪枝 ● float:权重总值★ 0:默认值 叶节点最小样本权重总值,如果叶节点的权重值小于这个值,则和兄弟节点一起被剪枝 ● float:权重总值★ 0:默认值
max_leaf_nodes 性能 最大叶节点数● int:个数★ None:不限制叶节点数 最大叶节点数● int:个数★ None:不限制叶节点数 最大叶节点数● int:个数★ None:不限制叶节点数 最大叶节点数● int:个数★ None:不限制叶节点数
bootstrap 性能 是否bootstrap对样本抽样● False:子模型的样本一致,子模型间强相关★ True:默认值 是否bootstrap对样本抽样● False:子模型的样本一致,子模型间强相关★ True:默认值    
subsample 性能     子采样率,选用一部分样本训练弱学习器 ● float:采样率★ 1.0:默认值 子采样率,选用一部分样本训练弱学习器 ● float:采样率★ 1.0:默认值
init 性能     初始子模型 初始子模型
n_jobs 效率 并行数● int:个数● -1:跟CPU核数一致★ 1:默认值 并行数● int:个数● -1:跟CPU核数一致★ 1:默认值    
warm_start 效率 是否热启动,如果是,则下一次训练是以追加树的形式进行● bool:热启动★ False:默认值 是否热启动,如果是,则下一次训练是以追加树的形式进行● bool:热启动★ False:默认值 是否热启动,如果是,则下一次训练是以追加树的形式进行● bool:热启动★ False:默认值 是否热启动,如果是,则下一次训练是以追加树的形式进行● bool:热启动★ False:默认值
presort 效率     是否预排序,预排序可以加速查找最佳分裂点,对于稀疏数据不管用● Bool★ auto:非稀疏数据则预排序,若稀疏数据则不预排序 是否预排序,预排序可以加速查找最佳分裂点,对于稀疏数据不管用● Bool★ auto:非稀疏数据则预排序,若稀疏数据则不预排序
oob_score 附加 是否计算袋外得分★ False:默认值 是否计算袋外得分★ False:默认值    
random_state 附加 随机器对象 随机器对象 随机器对象 随机器对象
verbose 附加 日志冗长度● int:冗长度★ 0:不输出训练过程● 1:偶尔输出● >1:对每个子模型都输出 日志冗长度● int:冗长度★ 0:不输出训练过程● 1:偶尔输出● >1:对每个子模型都输出 日志冗长度● int:冗长度★ 0:不输出训练过程● 1:偶尔输出● >1:对每个子模型都输出 日志冗长度● int:冗长度★ 0:不输出训练过程● 1:偶尔输出● >1:对每个子模型都输出

注:★ 表示默认值

不难发现,Random Forest模型和GBDT模型有不少共同的参数,然而某些参数的默认值又相差甚远。Random Forest的子模型都拥有较低的偏差,整体模型的训练过程旨在降低方差,故其需要较少的子模型(n_estimators默认值为10)且子模型不为弱模型(max_depth的默认值为None),同时,降低子模型间的相关度可以起到减少整体模型的方差的效果(max_features的默认值为auto)。另一方面,GBDT的子模型都拥有较低的方差,整体模型的训练过程旨在降低偏差,故其需要较多的子模型(n_estimators默认值为100)且子模型为弱模型(max_depth的默认值为3),但是降低子模型间的相关度不能显著减少整体模型的方差(max_features的默认值为None)。

如何调参

参数分类的目的在于缩小调参的范围,首先我们要明确训练的目标,把目标类的参数定下来。接下来,我们需要根据数据集的大小,考虑是否采用一些提高训练效率的策略,否则一次训练就三天三夜,法国人孩子都生出来了。然后,我们终于进入到了重中之重的环节:调整那些影响整体模型性能的参数。

调参的目标是为了达到偏差和方差的协调,从而降低模型的泛化误差。进一步,这些参数又可分为两类:过程影响类及子模型影响类。在子模型不变的前提下,某些参数可以通过改变训练的过程,从而影响模型的性能,诸如:“子模型数”(n_estimators)、“学习率”(learning_rate)等。另外,我们还可以通过改变子模型性能来影响整体模型的性能,诸如:“最大树深度”(max_depth)、“分裂条件”(criterion)等。正由于bagging的训练过程旨在降低方差,而boosting的训练过程旨在降低偏差,过程影响类的参数能够引起整体模型性能的大幅度变化。一般来说,在此前提下,我们继续微调子模型影响类的参数,从而进一步提高模型的性能。

假设模型是多个参数的函数,其输出值为模型的准确。我们可以固定其他参数,从而对某个参数对整体模型性能的影响进行分析:是正影响还是负影响,影响的单调性如何。

对Random Forest来说,增加“子模型数”(n_estimators)可以明显降低整体模型的方差,且不会对子模型的偏差和方差有任何影响。模型的准确度会随着“子模型数”的增加而提高。由于减少的是整体模型方差公式的第二项,故准确度的提高有一个上限。在不同的场景下,“分裂条件”(criterion)对模型的准确度的影响也不一样,该参数需要在实际运用时灵活调整。调整“最大叶节点数”(max_leaf_nodes)以及“最大树深度”(max_depth)之一,可以粗粒度地调整树的结构:叶节点越多或者树越深,意味着子模型的偏差越低,方差越高;同时,调整“分裂所需最小样本数”(min_samples_split)、“叶节点最小样本数”(min_samples_leaf)及“叶节点最小权重总值”(min_weight_fraction_leaf),可以更细粒度地调整树的结构:分裂所需样本数越少或者叶节点所需样本越少,也意味着子模型越复杂。一般来说,我们总采用bootstrap对样本进行子采样来降低子模型之间的关联度,从而降低整体模型的方差。适当地减少“分裂时考虑的最大特征数”(max_features),给子模型注入了另外的随机性,同样也达到了降低子模型之间关联度的效果。但是一味地降低该参数也是不行的,因为分裂时可选特征变少,模型的偏差会越来越大。在下图中,我们可以看到这些参数对Random Forest整体模型性能的影响:

集成学习

对Gradient Tree Boosting来说,“子模型数”(n_estimators)和“学习率”(learning_rate)需要联合调整才能尽可能地提高模型的准确度:想象一下,A方案是走4步,每步走3米,B方案是走5步,每步走2米,哪个方案可以更接近10米远的终点?同理,子模型越复杂,对应整体模型偏差低,方差高,故“最大叶节点数”(max_leaf_nodes)、“最大树深度”(max_depth)等控制子模型结构的参数是与Random Forest一致的。类似“分裂时考虑的最大特征数”(max_features),降低“子采样率”(subsample),也会造成子模型间的关联度降低,整体模型的方差减小,但是当子采样率低到一定程度时,子模型的偏差增大,将引起整体模型的准确度降低。还记得“初始模型”(init)是什么吗?不同的损失函数有不一样的初始模型定义,通常,初始模型是一个更加弱的模型(以“平均”情况来预测),虽说支持自定义,大多数情况下保持默认即可。在下图中,我们可以看到这些参数对Gradient Tree Boosting整体模型性能的影响: 
集成学习
到此为止,我们终于知道需要调整哪些参数,对于单个参数,我们也知道怎么调整才能提升性能。然而,表示模型的函数并不是一元函数,这些参数需要共同调整才能得到全局最优解。也就是说,把这些参数丢给调参算法(诸如Grid Search)咯?对于小数据集,我们还能这么任性,但是参数组合爆炸,在大数据集上,或许我的子子孙孙能够看到训练结果吧。实际上网格搜索也不一定能得到全局最优解,而另一些研究者从解优化问题的角度尝试解决调参问题。

坐标下降法是一类优化算法,其最大的优势在于不用计算待优化的目标函数的梯度。我们最容易想到一种特别朴实的类似于坐标下降法的方法,与坐标下降法不同的是,其不是循环使用各个参数进行调整,而是贪心地选取了对整体模型性能影响最大的参数。参数对整体模型性能的影响力是动态变化的,故每一轮坐标选取的过程中,这种方法在对每个坐标的下降方向进行一次直线搜索(line search)。首先,找到那些能够提升整体模型性能的参数,其次确保提升是单调或近似单调的。这意味着,我们筛选出来的参数是对整体模型性能有正影响的,且这种影响不是偶然性的,要知道,训练过程的随机性也会导致整体模型性能的细微区别,而这种区别是不具有单调性的。最后,在这些筛选出来的参数中,选取影响最大的参数进行调整即可。

无法对整体模型性能进行量化,也就谈不上去比较参数影响整体模型性能的程度。是的,我们还没有一个准确的方法来量化整体模型性能,只能通过交叉验证来近似计算整体模型性能。然而交叉验证也存在随机性,假设我们以验证集上的平均准确度作为整体模型的准确度,我们还得关心在各个验证集上准确度的变异系数,如果变异系数过大,则平均值作为整体模型的准确度也是不合适的。在接下来的案例分析中,我们所谈及的整体模型性能均是指平均准确度,请各位留心。

例子

具体见参考文献[6]

参考文献

[1] Zhu J, Zou H, Rosset S, et al. Multi-class AdaBoost[J]. Statistics & Its Interface, 2006, 2(3):349-360.

[2] Drucker H. Improving Regressors using Boosting Techniques[C]// Fourteenth International Conference on Machine Learning. Morgan Kaufmann Publishers Inc. 1997:107-115.

[3] 刘建平Pinard集成学习系列 http://www.cnblogs.com/pinard/category/894692.html

[4] GBDT理论知识总结(http://www.cnblogs.com/bentu*ng/p/6667267.html)

[5] 使用sklearn进行集成学习——理论(http://www.cnblogs.com/jasonfreak/p/5657196.html)

[6] 使用sklearn进行集成学习——实践(http://www.cnblogs.com/jasonfreak/p/5720137.html)

[7] 李航 《统计学习方法》