机器学习中的算法(1)-决策树模型组合之随机森林与GBDT

版权声明:html

    本文由LeftNotEasy发布于http://leftnoteasy.cnblogs.com, 本文能够被所有的转载或者部分使用,但请注明出处,若是有问题,请联系wheeleast@gmail.com算法

 

前言:apache

    决策树这种算法有着不少良好的特性,好比说训练时间复杂度较低,预测的过程比较快速,模型容易展现(容易将获得的决策树作成图片展现出来)等。可是同时,单决策树又有一些很差的地方,好比说容易over-fitting,虽然有一些方法,如剪枝能够减小这种状况,可是仍是不够的。app

    模型组合(好比说有Boosting,Bagging等)与决策树相关的算法比较多,这些算法最终的结果是生成N(可能会有几百棵以上)棵树,这样能够大大的减小单决策树带来的毛病,有点相似于三个臭皮匠等于一个诸葛亮的作法,虽然这几百棵决策树中的每一棵都很简单(相对于C4.5这种单决策树来讲),可是他们组合起来确是很强大。框架

    在最近几年的paper上,如iccv这种重量级的会议,iccv 09年的里面有很多的文章都是与Boosting与随机森林相关的。模型组合+决策树相关的算法有两种比较基本的形式 - 随机森林与GBDT((Gradient Boost Decision Tree),其余的比较新的模型组合+决策树的算法都是来自这两种算法的延伸。本文主要侧重于GBDT,对于随机森林只是大概提提,由于它相对比较简单。dom

    在看本文以前,建议先看看机器学习与数学(3)与其中引用的论文,本文中的GBDT主要基于此,而随机森林相对比较独立。机器学习

 

基础内容:函数

    这里只是准备简单谈谈基础的内容,主要参考一下别人的文章,对于随机森林与GBDT,有两个地方比较重要,首先是information gain,其次是决策树。这里特别推荐Andrew Moore大牛的Decision Trees Tutorial,与Information Gain Tutorial。Moore的Data Mining Tutorial系列很是赞,看懂了上面说的两个内容以后的文章才能继续读下去。学习

    决策树其实是将空间用超平面进行划分的一种方法,每次分割的时候,都将当前的空间一分为二,好比说下面的决策树:spa

image

    就是将空间划分红下面的样子:

image

    这样使得每个叶子节点都是在空间中的一个不相交的区域,在进行决策的时候,会根据输入样本每一维feature的值,一步一步往下,最后使得样本落入N个区域中的一个(假设有N个叶子节点)

 

 

随机森林(Random Forest):

    随机森林是一个最近比较火的算法,它有不少的优势:

  •     在数据集上表现良好
  •     在当前的不少数据集上,相对其余算法有着很大的优点
  •     它可以处理很高维度(feature不少)的数据,而且不用作特征选择
  •     在训练完后,它可以给出哪些feature比较重要
  •     在建立随机森林的时候,对generlization error使用的是无偏估计
  •     训练速度快
  •     在训练过程当中,可以检测到feature间的互相影响
  •     容易作成并行化方法
  •     实现比较简单

    随机森林顾名思义,是用随机的方式创建一个森林,森林里面有不少的决策树组成,随机森林的每一棵决策树之间是没有关联的。在获得森林以后,当有一个新的输入样本进入的时候,就让森林中的每一棵决策树分别进行一下判断,看看这个样本应该属于哪一类(对于分类算法),而后看看哪一类被选择最多,就预测这个样本为那一类。

    在创建每一棵决策树的过程当中,有两点须要注意 - 采样与彻底分裂。首先是两个随机采样的过程,random forest对输入的数据要进行行、列的采样。对于行采样,采用有放回的方式,也就是在采样获得的样本集合中,可能有重复的样本。假设输入样本为N个,那么采样的样本也为N个。这样使得在训练的时候,每一棵树的输入样本都不是所有的样本,使得相对不容易出现over-fitting。而后进行列采样,从M个feature中,选择m个(m << M)。以后就是对采样以后的数据使用彻底分裂的方式创建出决策树,这样决策树的某一个叶子节点要么是没法继续分裂的,要么里面的全部样本的都是指向的同一个分类。通常不少的决策树算法都一个重要的步骤 - 剪枝,可是这里不这样干,因为以前的两个随机采样的过程保证了随机性,因此就算不剪枝,也不会出现over-fitting。

    按这种算法获得的随机森林中的每一棵都是很弱的,可是你们组合起来就很厉害了。我以为能够这样比喻随机森林算法:每一棵决策树就是一个精通于某一个窄领域的专家(由于咱们从M个feature中选择m让每一棵决策树进行学习),这样在随机森林中就有了不少个精通不一样领域的专家,对一个新的问题(新的输入数据),能够用不一样的角度去看待它,最终由各个专家,投票获得结果。

    随机森林的过程请参考Mahout的random forest 。这个页面上写的比较清楚了,其中可能不明白的就是Information Gain,能够看看以前推荐过的Moore的页面。

 

 

Gradient Boost Decision Tree:

   GBDT是一个应用很普遍的算法,能够用来作分类、回归。在不少的数据上都有不错的效果。GBDT这个算法还有一些其余的名字,好比说MART(Multiple Additive Regression Tree),GBRT(Gradient Boost Regression Tree),Tree Net等,其实它们都是一个东西(参考自wikipedia – Gradient Boosting),发明者是Friedman

   Gradient Boost实际上是一个框架,里面能够套入不少不一样的算法,能够参考一下机器学习与数学(3)中的讲解。Boost是"提高"的意思,通常Boosting算法都是一个迭代的过程,每一次新的训练都是为了改进上一次的结果。

   原始的Boost算法是在算法开始的时候,为每个样本赋上一个权重值,初始的时候,你们都是同样重要的。在每一步训练中获得的模型,会使得数据点的估计有对有错,咱们就在每一步结束后,增长分错的点的权重,减小分对的点的权重,这样使得某些点若是总是被分错,那么就会被“严重关注”,也就被赋上一个很高的权重。而后等进行了N次迭代(由用户指定),将会获得N个简单的分类器(basic learner),而后咱们将它们组合起来(好比说能够对它们进行加权、或者让它们进行投票等),获得一个最终的模型。

   而Gradient Boost与传统的Boost的区别是,每一次的计算是为了减小上一次的残差(residual),而为了消除残差,咱们能够在残差减小的梯度(Gradient)方向上创建一个新的模型。因此说,在Gradient Boost中,每一个新的模型的简历是为了使得以前模型的残差往梯度方向减小,与传统Boost对正确、错误的样本进行加权有着很大的区别。

   在分类问题中,有一个很重要的内容叫作Multi-Class Logistic,也就是多分类的Logistic问题,它适用于那些类别数>2的问题,而且在分类结果中,样本x不是必定只属于某一个类能够获得样本x分别属于多个类的几率(也能够说样本x的估计y符合某一个几何分布),这其实是属于Generalized Linear Model中讨论的内容,这里就先不谈了,之后有机会再用一个专门的章节去作吧。这里就用一个结论:若是一个分类问题符合几何分布,那么就能够用Logistic变换来进行以后的运算

   假设对于一个样本x,它可能属于K个分类,其估计值分别为F1(x)…FK(x),Logistic变换以下,logistic变换是一个平滑且将数据规范化(使得向量的长度为1)的过程,结果为属于类别k的几率pk(x),

image

   对于Logistic变换后的结果,损失函数为:

image    其中,yk为输入的样本数据的估计值,当一个样本x属于类别k时,yk = 1,不然yk = 0。

    将Logistic变换的式子带入损失函数,而且对其求导,能够获得损失函数的梯度

image    上面说的比较抽象,下面举个例子:

    假设输入数据x可能属于5个分类(分别为1,2,3,4,5),训练数据中,x属于类别3,则y = (0, 0, 1, 0, 0),假设模型估计获得的F(x) = (0, 0.3, 0.6, 0, 0),则通过Logistic变换后的数据p(x) = (0.16,0.21,0.29,0.16,0.16),y - p获得梯度g:(-0.16, -0.21, 0.71, -0.16, -0.16)。观察这里能够获得一个比较有意思的结论:

    假设gk为样本当某一维(某一个分类)上的梯度:

    gk>0时,越大表示其在这一维上的几率p(x)越应该提升,好比说上面的第三维的几率为0.29,就应该提升,属于应该往“正确的方向”前进

                  越小表示这个估计越“准确”

    gk<0时,越小,负得越多表示在这一维上的几率应该下降,好比说第二维0.21就应该获得下降。属于应该朝着“错误的反方向”前进

                  越大,负得越少表示这个估计越“不错误 ”

    总的来讲,对于一个样本,最理想的梯度是越接近0的梯度。因此,咱们要可以让函数的估计值可以使得梯度往反方向移动(>0的维度上,往负方向移动,<0的维度上,往正方向移动)最终使得梯度尽可能=0),而且该算法在会严重关注那些梯度比较大的样本,跟Boost的意思相似

 

 

    获得梯度以后,就是如何让梯度减小了。这里是用的一个迭代+决策树的方法,当初始化的时候,随便给出一个估计函数F(x)(可让F(x)是一个随机的值,也可让F(x)=0),而后以后每迭代一步就根据当前每个样本的梯度的状况,创建一棵决策树。就让函数往梯度的反方向前进,最终使得迭代N步后,梯度越小。

    这里创建的决策树和普通的决策树不太同样,首先,这个决策树是一个叶子节点数J固定的,当生成了J个节点后,就再也不生成新的节点了。

    算法的流程以下:(参考自treeBoost论文)

image

     0. 表示给定一个初始值

     1. 表示创建M棵决策树(迭代M次)

     2. 表示对函数估计值F(x)进行Logistic变换

     3. 表示对于K个分类进行下面的操做(其实这个for循环也能够理解为向量的操做,每个样本点xi都对应了K种可能的分类yi,因此yi, F(xi), p(xi)都是一个K维的向量,这样或许容易理解一点)

     4. 表示求得残差减小的梯度方向

     5. 表示根据每个样本点x,与其残差减小的梯度方向,获得一棵由J个叶子节点组成的决策树

     6. 为当决策树创建完成后,经过这个公式,能够获得每个叶子节点的增益(这个增益在预测的时候用的)

       每一个增益的组成其实也是一个K维的向量,表示若是在决策树预测的过程当中,若是某一个样本点掉入了这个叶子节点,则其对应的K个分类的值是多少。好比说,GBDT获得了三棵决策树,一个样本点在预测的时候,也会掉入3个叶子节点上,其增益分别为(假设为3分类的问题):

       (0.5, 0.8, 0.1),  (0.2, 0.6, 0.3),  (0.4, 0.3, 0.3),那么这样最终获得的分类为第二个,由于选择分类2的决策树是最多的。

     7. 的意思为,将当前获得的决策树与以前的那些决策树合并起来,做为新的一个模型(跟6中所举的例子差很少)

     GBDT的算法大概就讲到这里了,但愿可以弥补一下上一篇文章中没有说清楚的部分:)

 

 

实现:

     看明白了算法,就须要去实现一下,或者看看别人实现的代码,这里推荐一下wikipedia中的gradient boosting页面,下面就有一些开源软件中的一些实现,好比说下面这个:http://elf-project.sourceforge.net/ 

 

参考资料:

     除了文章中的引用的内容(已经给出了连接)外,主要仍是参考Friedman大牛的文章:Greedy function approximation : A Gradient Boosting Machine

相关文章
相关标签/搜索