2015/11/21 16:29:29 by guhaohit

导语:

GBDT是非常有用的机器学习的其中一个算法,目前广泛应用于各个领域中(regression,classification,ranking)。这篇文章是我自己对GBDT的总结加上自己的一些理解,所以中间一些内容并不全都是个人的原创。由于自身水平有限,可能会有错误,主要是为了让自己加强对GBDT的理解。

一,GBDT简介:

GBDT的中文名叫做梯度提升决策树。由名字我们就可以看出,这个算法是由两部分构成的,梯度提升和决策树,而GBDT就是用简单决策树作为基分类器的梯度提升方法。
对于决策树,在这里不多做介绍,树形结构,建立决策树的关键,即在当前状态下选择哪个属性作为分类依据。根据不同的目标函数,建立决策树主要有三种算法:ID3,C4.5和CART。具体内容可以参考@李航老师的《统计学习方法》。接下来我将重点说一说梯度提升。

二,梯度提升:

Gradient Boosting = Gradient Descent + Boosting

梯度提升其实就是一种提升方法(Boosting)。我们最熟悉的应用boosting的算法就是Adaboost了,利用多个弱分类器,通过加法模型(ensemble)的方式组合起来,得到效果不错的分类器。为了更好的理解boosting这个方法,我想先介绍前向分步算法,然后再来介绍梯度提升。

1. 前向分布算法

先说结论:Adaboost算法可以理解为加法模型(additive model)、损失函数为指数函数、学习算法为前向分布算法的二类分类学习算法。

下面给出加法模型的表达式:
$$H(x) = sum_{t}{rho_{t}h_t(x)}$$
其中 $t$ 表示弱分类器的数量,$h_t(x)$表示弱分类器,$rho_{t}$表示该弱分类器的权重。
简单来说,前向分布算法就是在多轮迭代中,每次引入一个弱分类器来弥补我们已有的分类器的缺陷。

在Adaboost算法中,我们定义缺陷为高权重的数据。我们生成的新弱分类器优先将高权重的数据拟合,而将拟合的好的数据的权重降低,将拟合的不好的数据的权重提高,从而在下个弱分类器中能更重视这些分错的数据。

2. Boost方法

对于一个问题,如果存在一个多项式的学习算法能学习,并且正确率很高,那么就称为强可学习的;如果正确率仅比随机猜测略好,则称为弱可学习的。在PAC (probably approximately correct)学习框架下,强可学习与弱可学习是等价的。

对于一个分类问题,我们存在两种类型的分类器:强分类器和弱分类器,相对于强分类器,弱分类器更容易得到。这样一来,如果我们已经得到了“弱学习算法”,那么我们能否将它提升(boost)为“强学习算法”。
对于提升算法而言,有两个问题需要解决:1.找到当前弱分类器的缺陷。2.将弱分类器组合起来,弥补缺陷,得到一个强分类器。
对于Adaboost算法来说,找到弱分类器的缺陷为错分的数据,通过改变数据的权值并采用加权投票的方式来弥补缺陷。

3. 梯度提升(Gradient Boosting)

这里我解释梯度提升为利用梯度下降的思想,通过拟合梯度的方法来将弱分类器提升为强分类器。

在Gradient Boosting算法中,我们定义缺陷为梯度。有可能会有疑问,为什么可以把梯度定义为缺陷呢?先来回顾下梯度下降的概念:
$$theta_{i}:=theta_{i}-rho frac{partial{J}}{partial{theta_{i}}}$$

将$f(x)$泰勒展开$f(x+varepsilon)=f(x)+frac{partial{f(x)}}{partial{x}}varepsilon +O(x^2)$,我们想让$f(x+varepsilon)-f(x)<0$,即$frac{partial{f(x)}}{partial{x}}varepsilon <0$,所以我们取$varepsilon = -frac{partial{f(x)}}{partial{x}}$使得$frac{partial{f(x)}}{partial{x}}varepsilon $最小,所以梯度下降又被称为最速梯度下降法。

假设我们的模型为$F(x)$,Loss function为$L(y,F(x))=sum_{i}{L(y_{i},F(x_i))}$,我们需要调整$F(x_i)$使得Loss function最小。我们将$F(x_i)$当作之前的参数$theta_i$求偏导$frac{partial{L(y_{i},F(x_i))}}{partial{F(x_i)}}$,然后我们需要做的就是更新参数:
$$F_{new}(x_i) = F(x_i)-rho times frac {partial{L(y_{i},F(x_i))}}{partial{F(x_i)}} $$
上式中,$x_i$表示一个样本点,对于训练集中的所有点,都满足上式。请注意一点,这里的$F(x)$是我们的模型,我们通过一次迭代,得到了一个新的模型,由梯度下降的定理来说,这个新的$F(x)$对于训练集上的所有的点,使得我们的Loss function更小。
到此为止,我们得到了一个惊喜的发现,我们找到了公式,能使得我们的模型变的更好。现在我们需要解决的就是,将所求得的梯度值拟合出来。后面的事很容易想到,我们使用决策树来拟合这个梯度,得到新的公式:
$$F_{n+1}(x) = F_{n}(x) + eta times T_{n+1}(x)$$
其中$T_{n+1}$表示的通过拟合$F_{n}(x)$的梯度得到的决策树,$eta$可以看成是$-rho$。

4. 梯度提升应用于回归问题

对于梯度提升方法,可以应用于regression,classification,ranking等多个方面,而难度也是逐渐增加。

对于回归问题,由之前的分析,很容易给出相对应算法:

give any differentiable loss function L:
start with an initial model, set $F(x) =frac{sum_{i=1}^{n}{y_i}}{n}$
iterate until converge:
calculate negative gradients $-g(x_i)=-frac {partial{L(y_{i},F(x_i))}}{partial{F(x_i)}}$
fit a regression tree h to negative gradients $-g(x_i)$
$F:=F+rho h$

其中$rho$可以采用求极值的方式进行求解,使得Loss function最小。
对于机器学习算法来说都会存在过拟合的问题,如果我们得到的拟合梯度的决策树太复杂或者树的个数过多的话,容易出现过拟合的现象,我们将采用正 大专栏  GBDT的理解和总结则化的方法来保证我们的模型不会过拟合。
可以采用CART剪枝的方法来对每次的生成树进行控制,并且加入正则项$lambda |T|$,其中$|T|$表示当前已有的树的数目,也可以将T当成参数来调整。
在实际项目中,经常用到一种叫做shrinkage的方法,就是它不完全信任每一个棵拟合梯度的树,它认为每棵树只学到了真理的一小部分,累加的时候只累加一小部分,通过多学几棵树弥补不足。用方程来看更清晰,即:
$$F_{n+1}(x)=F_{n}(x)+upsilon times eta T_{n+1}(x)$$
一个有趣的现象就是当$upsilon$越小时,$|T|$的值越大,这些值都可以当做参数在验证集中调整。shrinkage方法在实际应用中非常有效,但是目前缺少相应的理论证明。

5. 梯度提升应用于分类问题

假设我们要将数据分为$K$类,我们建立$K$个模型$F_{1}(x),F_{2}(x),…F_{K}(x)$,采用信息熵的思想,我们转化成概率值:
$$P_{i}(x)=frac {e^{F_{i}(x)}}{sum_{c=1}^{K}{e^{F_{c}(x)}}}$$
上式代表了当前数据x于第i类的概率值。对于每一个数据,可得到$P(x)=[P_{1}(x),P_{2}(x),…P_{K}(x)]$,假设这个数据属于第j类,那么$Y=[0,…,1,…,0]$,我们建立Loss function为$L(P(x),Y)$,有很多这样的函数,比如softmax回归的目标函数和KL-divergence。
接下来就跟之前说的回归问题的解法一样了,唯一的区别就是我们每次要得到K棵树来更新K个模型。

三. 梯度提升的进阶

前面说的梯度提升的方法是通过拟合梯度,而梯度由泰勒展开推导出来的,能否能利用Loss function的二阶导数呢?

我们直接从Loss function的泰勒展开开始:
$$begin{split}
L(y,F_{n}(x))&=sum_{i}{L(y_{i},F_{n}(x_i))}\
&=sum_{i}{L(y_{i},F_{n-1}(x_i)+T_{n}(x_{i}))}\
&=sum_{i}left[ { L(y_{i},F_{n-1}(x_i))} + g_{i}^{n-1}T_{n}(x_i)+frac{1}{2}h_{i}^{n-1}T_{n}^2(x_i)right]
end{split}$$
其中,$g_{i}^{n-1}=frac{partial{L(y_{i},F_{n-1}(x_i))}}{partial{F_{n-1}(x_i)}}$,$h_{i}^{n-1}=frac{partial^{2}{L(y_{i},F_{n-1}(x_i))}}{partial^{2}{F_{n-1}(x_i)}}$。
很容易得到:
$$L(y,F_{n}(x))-L(y,F_{n-1}(x))=sum_{i}left[ g_{i}^{n-1}T_{n}(x_i)+frac{1}{2}h_{i}^{n-1}T_{n}^2(x_i)right]$$
很容易得到,当$T_{n}(x_{i})=-frac{g_{i}^{n-1}}{h_{i}^{n-1}}$时,能使得上式左边最小,即$L(y,F_{n}(x))-L(y,F_{n-1}(x))=sum_{i}left[ -frac{(g_{i}^{n-1})^2}{2h_{i}^{n-1}}right]$,只有当$h_{i}^{n-1}>0$的时候才能满足。再回过头看一看$h_{i}^{n-1}$的定义,它是我们Loss function关于$F(x)$的二阶偏导,当Loss function是下凸函数时,能满足$h_{i}^{n-1}>0$这个条件。细心的人应该已经发现了,其实这个就是牛顿法的变形。接下来我们只需要用决策树来拟合$-frac{g_{i}^{n-1}}{h_{i}^{n-1}}$就好了。

之后看来@陈天奇怪同学写的关于GBDT的文章,看到他讲解了引入正则化的方法,而且xgboost也是用的这种方式进行的实现。

我们对目标式子中加入正则化(对生成的树进行限制):
$$begin{split}
Obj^{(n)}&=L(y,F_{n}(x))-L(y,F_{n-1}(x))\
&=sum_{i}left[ g_{i}^{n-1}T_{n}(x_i)+frac{1}{2}h_{i}^{n-1}T_{n}^2(x_i)right]+Omega left( T_{n} right)
end{split}$$
我们先来定义树的结构,假设生成的树有M个叶子节点,每一个x最后会投影到其中一个叶子节点上,我们定义这个投影为$q(x): mathscr{R}^drightarrow { { 1,2,…,M }}$,每个叶子节点的输出值为$w_{1},w_{2},…,w_{M}in mathscr{R}$,我们生成的树为:$T_{n}(x)=w_{q(x)}$。
而对于正则化项,我们这样定义:$Omega left( T_{n} right)=gamma M+frac{1}{2}lambda sum_{j=1}^{M}{w_{j}^2}$。正则化项分为两部分,叶子节点数目和叶子节点的输出值,这不是正则化项的唯一定义形式,我这用的是@陈天奇怪ppt中的方法。
$$begin{split}
Obj^{(n)}&=sum_{i}left[ g_{i}^{n-1}T_{n}(x_i)+frac{1}{2}h_{i}^{n-1}T_{n}^2(x_i)right]+Omega left( T_{n} right) \
&=sum_{i}left[ g_{i}^{n-1}T_{n}(x_i)+frac{1}{2}h_{i}^{n-1}T_{n}^2(x_i)right]+gamma M+frac{1}{2}lambda sum_{j=1}^{M}{w_{j}^2} \
&=sum_{j=i}^{M}left[ left(sum_{iin I_{j}}{g_{i}^{n-1}} right)w_{j}+
frac{1}{2}left( sum_{iin I_{j}}{h_{i}^{n-1}+lambda} right)w_{j}^2 + gamma Mright] \
&=sum_{j=i}^{M}left[ G_{j}w_{j}+
frac{1}{2}left( H_{j}+lambda right) w_{j}^2 + gamma Mright]
end{split}$$
上式中,$I_{j}$表示j叶子节点中样本的集合,$I_{j}={ i ,|, q(x_{i}=j)}$。$G_{j}=sum_{iin I_{j}}{g_{i}^{n-1}}$,$H_{j}=sum_{iin I_{j}}{h_{i}^{n-1}}$。
现在我们对于每一个叶子节点,$w_j=-frac{G_{j}}{H_{j}+lambda}$时能得到最小值,最小值为$-frac{1}{2}sum_{j=1}^{M}{frac{G_{j}^2}{H_{j}+lambda}+gamma M}$。
最后说一说这种方法的生成树的方法,将数据集合按照决策树的方法进行分裂(split),但是我们定义一种新的分裂标准:
$$Gain = frac{G_{L}^2}{H_{L}+lambda}+frac{G_{R}^2}{H_{R}+lambda}-frac{left( G_{L}+G_{R}right)^2}{ H_{L}+H_{R}+lambda}-gamma$$
这表示把一棵树的一个结点分裂成两棵子树后Loss function减小的值,我们找到$Gain$最大的分裂方法即可。
我们可以看到,我们要求$H_{j}+lambda>0$,对比于之前我们没有加入正则化项之前的要求,已经放松很多了,需要叶子节点所有的样本的二阶偏导之和大于$-lambda$即可。
我们还可以通过剪枝来优化我们的方法,生成树之后,从下往上,将$Gain<0$的子树剪掉。

参考资料:

  1. Introduction to Boosted Trees by 陈天奇
  2. A Discussion on GBDT: Gradient Boosting Decision Tree by Tom
  3. A Gentle Introduction to Gradient Boosting by Cheng Li

GBDT的理解和总结的更多相关文章

  1. [Machine Learning & Algorithm] 决策树与迭代决策树(GBDT)

    谈完数据结构中的树(详情见参照之前博文<数据结构中各种树>),我们来谈一谈机器学习算法中的各种树形算法,包括ID3.C4.5.CART以及基于集成思想的树模型Random Forest和G ...

  2. GBDT原理详解

    从提升树出发,——>回归提升树.二元分类.多元分类三个GBDT常见算法. 提升树 梯度提升树 回归提升树 二元分类 多元分类 面经 提升树 在说GBDT之前,先说说提升树(boosting tr ...

  3. GBDT 总结文档

    在做阿里的o2o优惠券预测的时候学习了GBDT.听闻GBDT的威力,自然要学习学习. 接下来从以下几个方面记录下我对于GBDT的理解. GBDT的用途,优势 GBDT的结构和算法流程 GBDT如何训练 ...

  4. GBDT 算法

    GBDT (Gradient Boosting Decision Tree) 梯度提升迭代决策树.GBDT 也是 Boosting 算法的一种,但是和 AdaBoost 算法不同(AdaBoost 算 ...

  5. 一步一步理解GB、GBDT、xgboost

    GBDT和xgboost在竞赛和工业界使用都非常频繁,能有效的应用到分类.回归.排序问题,虽然使用起来不难,但是要能完整的理解还是有一点麻烦的.本文尝试一步一步梳理GB.GBDT.xgboost,它们 ...

  6. (转)GBDT迭代决策树理解

    在网上看到一篇对从代码层面理解gbdt比较好的文章,转载记录一下: GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Re ...

  7. gbdt xgboost 贼难理解!

    https://www.zybuluo.com/yxd/note/611571 https://zhuanlan.zhihu.com/p/29765582 gbdt 在看统计学习方法的时候 理解很吃力 ...

  8. GBDT理解

    一.提升树 提升方法实际采用加法模型(即基函数的线性组合)与前向分布算法.以决策树为基函数的提升方法称为提升树,boosting tree.对分类问题的决策树是二叉分类树,对回归问题的决策树是二叉回归 ...

  9. 大白话5分钟带你走进人工智能-第31节集成学习之最通俗理解GBDT原理和过程

    目录 1.前述 2.向量空间的梯度下降: 3.函数空间的梯度下降: 4.梯度下降的流程: 5.在向量空间的梯度下降和在函数空间的梯度下降有什么区别呢? 6.我们看下GBDT的流程图解: 7.我们看一个 ...

随机推荐

  1. vue组件传值 part2

    非父子组件传值 轻量级 视图层框架 复杂组件间传值,引进其他的工具或者设计模式 1.vuex 2.总线机制 //main line 1.在main.js中注册全局的bus Vue.prototype. ...

  2. js判断苹果和安卓端或者wp端

    最近做了一个H5,说要提供一个底部,可以区分安卓或者ios,到相应的网址进行下载APP,如图: 代码如下:  window.onload = function () { var u = navigat ...

  3. ELK简单配置

    input { file { path => ["/usr/local/kencery/tomcat/logs/catalina.out"] type => " ...

  4. js中要声明变量吗?

    你好,js语言是弱类型语言,无需申明即可直接使用,默认是作为全局变量使用的.建议:在function里时应使用var 申明变量,这样改变量仅仅只在function的生存周期内存在,不会污染到,全局控件 ...

  5. 一个简单WebApp的全程

    开始前,我先给出上一篇选项卡的demo链接http://xqhuadou.com/demo1/index.html.相信看着应该很带感,不过这个是之前经过修改的. 制作过程我就不多说了,可以直接看源码 ...

  6. NOIp2017TG解题报告

    NOIp2018RP++! 虽然没去但还得写写QAQ D1T1 : 小凯的疑惑 数学题 手推几组数据然后发现规律 \(Ans = (a-1)(b-1)+1\) AC in 1minite D1T2 : ...

  7. 7)get方式提交表单和简单处理

    一个带有html的代码:   hello.php <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" ...

  8. Java字符串替换函数replace、replaceFirst、replaceAll

    一.replace(String old,String new) 功能:将字符串中的所有old子字符串替换成new字符串 示例 String s="Hollow world!"; ...

  9. Codeforces 1293A - ConneR and the A.R.C. Markland-N

    题目大意: ConneR老师想吃东西,他现在在大楼的第s层,大楼总共有n层,但是其中有k层的餐厅关门了. 然后给了这k层关门的餐厅分别所在的楼层. 所以问ConneR老师最少得往上(或者往下)走几层楼 ...

  10. Java/Oracle/mySQL 日期格式

    Java: yyyy-MM-dd HH:mm:ss.SSS Oracel: yyyy-MM-dd HH24:mi:ss select * from to_pub_report where report ...