机器学习算法总结(四)——GBDT与XGBOOST

  Boosting方法实际上是采用加法模型与前向分布算法。在上一篇提到的Adaboost算法也可以用加法模型和前向分布算法来表示。以决策树为基学习器的提升方法称为提升树(Boosting Tree)。对分类问题决策树是CART分类树,对回归问题决策树是CART回归树。

1、前向分布算法

  引入加法模型

  

  在给定了训练数据和损失函数L(y, f(x)) 的条件下,可以通过损失函数最小化来学习加法模型

  

  然而对于这个问题是个很复杂的优化问题,而且要训练的参数非常的多,前向分布算法的提出就是为了解决模型的优化问题,其核心思想是因为加法模型是由多各模型相加在一起的,而且在Boosting中模型之间又是有先后顺序的,因此可以在执行每一步加法的时候对模型进行优化,那么每一步只需要学习一个模型和一个参数,通过这种方式来逐步逼近全局最优,每一步优化的损失函数:

  

  具体算法流程如下:

  1)初始化f0(x) = 0;

  2)第m次迭代时,极小化损失函数

  

  3)更新模型,则fm(x):

  

  4)得到最终的加法模型

  

  Adaboost算法也可以用前向分布算法来描述,在这里输入的数据集是带有权重分布的数据集,损失函数是指数损失函数。

2、GBDT算法

  GBDT是梯度提升决策树(Gradient Boosting Decision Tree)的简称,GBDT可以说是最好的机器学习算法之一。GBDT和Adaboost一样可以用前向分布算法来描述,不同之处在于Adaboost算法每次拟合基学习器时,输入的样本数据是不一样的(每一轮迭代时的样本权重不一致),因此Adaboost旨在重点关注上一轮分类错误的样本,GBDT算法在每一步迭代时是输出的值不一样,本轮要拟合的输出值是和之前的模型的预测值和真实值的差值(模型的残差,也成为损失)。用于一个简单的例子来说明GBDT,假如某人的年龄为30岁,第一次用20岁去拟合,发现损失还有10岁,第二次用6岁去拟合10岁,发现损失还有4岁,第三次用3岁去拟合4岁,依次下去直到损失在我们可接受范围内。

  以平方误差损失函数的回归问题为例,来看看以损失来拟合是个什么样子,采用前向分布算法:

  

  在第m次迭代时,我们要优化的损失函数:

  

  此时我们采用平方误差损失函数为例:

  

  则上面损失函数变为:

  

  问题就成了对残差r的拟合了

  然而对于大多数损失函数,却没那么容易直接获得模型的残差,针对该问题,大神Freidman提出了用损失函数的负梯度来拟合本轮损失的近似值,拟合一个回归树

  

  关于GBDT一般损失函数的具体算法流程如下:

  1)初始化f0(x):

  

  2)第m次迭代时,计算当前要拟合的残差rmi

   

  以rmi为输出值,对rmi拟合一个回归树(此时只是确定了树的结构,但是还未确定叶子节点中的输出值),然后通过最小化当前的损失函数,并求得每个叶子节点中的输出值cmj,j表示第j个叶子节点

  

  更新当前的模型fm(x)为:

  

  3)依次迭代到我们设定的基学习器的个数M,得到最终的模型,其中M表示基学习器的个数,J表示叶子节点的个数

  

  GBDT算法提供了众多的可选择的损失函数,通过选择不同的损失函数可以用来处理分类、回归问题,比如用对数似然损失函数就可以处理分类问题。大概的总结下常用的损失函数:

  1)对于分类问题可以选用指数损失函数、对数损失函数。

  2)对于回归问题可以选用均方差损失函数、绝对损失函数。

  3)另外还有huber损失函数和分位数损失函数,也是用于回归问题,可以增加回归问题的健壮性,可以减少异常点对损失函数的影响。

3、GBDT的正则化

  在Adaboost中我们会对每个模型乘上一个弱化系数(正则化系数),减小每个模型对提升的贡献(注意:这个系数和模型的权重不一样,是在权重上又乘以一个0,1之间的小数),在GBDT中我们采用同样的策略,对于每个模型乘以一个系数λ (0 < λ ≤ 1),降低每个模型对拟合损失的贡献,这种方法也意味着我们需要更多的基学习器。

  第二种是每次通过按比例(推荐[0.5, 0.8] 之间)随机抽取部分样本来训练模型,这种方法有点类似Bagging,可以减小方差,但同样会增加模型的偏差,可采用交叉验证选取,这种方式称为子采样。采用子采样的GBDT有时也称为随机梯度提升树(SGBT)。

  第三种就是控制基学习器CART树的复杂度,可以采用剪枝正则化。

4、GBDT的优缺点

  GBDT的主要优点:

  1)可以灵活的处理各种类型的数据

  2)预测的准确率高

  3)使用了一些健壮的损失函数,如huber,可以很好的处理异常值

  GBDT的缺点:

  1)由于基学习器之间的依赖关系,难以并行化处理,不过可以通过子采样的SGBT来诗选部分并行。

5、XGBoost算法

5.1 定义树的复杂度

  首先把树拆分成结构部分q和叶子节点权重部分w,在这里w是一个向量,表示各叶子节点中的输出值

  

  具体表现示例如下,引入正则化项 Ω(ft) 来控制树的复杂度,从而实现有效的控制模型的过拟合

  

5.2 XGBoost中的Boosting Tree模型

  

  和GBDT方法一样,XGBoost的提升模型也是采用残差,不同的是分裂结点选取的时候不一定是最小平方损失,其损失函数如下,较GBDT其根据树模型的复杂度加入了一项正则化项:

  

5.3 对目标函数进行改写

  

  在GBDT中我们通过求损失函数的负梯度(一阶导数),利用负梯度替代残差来拟合树模型。在XGBoost中直接用泰勒展开式将损失函数展开成二项式函数(前提是损失函数一阶、二阶;连续可导),假设此时我们定义好了树的结构(在后面介绍,和GBDT中直接用残差拟合不同),假设我们的叶节点区域为:

  

  则我们的目标优化函数可以转换成:

  

  此时我们对wj求导并令导数为0,可得:

    

5.4 树结构的打分函数

  上面的Obj值代表当指定一个树结构时,在目标上面最多减少多少,我们可以把它称为结构分数。可以认为这是一个类似与基尼指数一样更一般的对树结构进行打分的函数。如下面的例子所示

  

  对于求得Obj分数最小的树结构,我们可以枚举所有的可能性,然后对比结构分数来获得最优的树结构,然而这种方法计算消耗太大,更常用的是贪心法,每次尝试对已经存在的叶节点(最开始的叶节点是根节点)进行分割,然后获得分割后的增益为:

  

  在这里以Gain作为判断是否分割的条件,如果Gain < 0,则此叶节点不做分割,然而这样对于每次分割还是需要列出所有的分割方案。而实际中我们先将所有样本按照gi从小到大排序,然后进行遍历,查看每个节点是否需要分割,具体示例如下:

  

  这样的分割方式,我们就只要对样本扫描一遍,就可以分割出GL,GR,然后根据Gain的分数进行分割

5.5 XGBoost中其他的正则化方法

  1)像Adaboost和GBDT中一样,对每一个模型乘以一个系数λ(0 < λ ≤ 1),用来降低每个模型对结果的贡献

  2)采用特征子采样方法,和RandomForest中的特征子采样一样,可以降低模型的方差

6、XGBoost和GBDT的区别

   1)将树模型的复杂度加入到正则项中,来避免过拟合,因此泛化性能会由于GBDT

   2)损失函数是用泰勒展开式展开的,同时用到了一阶导和二阶导,可以加快优化速度

  3)和GBDT只支持CART作为基分类器之外,还支持线性分类器,在使用线性分类器的时候可以使用L1,L2正则化

  4)引进了特征子采样,像RandomForest那样,这种方法既能降低过拟合,还能减少计算

  5)在寻找最佳分割点时,考虑到传统的贪心算法效率较低,实现了一种近似贪心算法,用来加速和减小内存消耗,除此之外还考虑了稀疏数据集和缺失值的处理,对于特征的值有缺失的样本,XGBoost依然能自动找到其要分裂的方向

  6)XGBoost支持并行处理,XGBoost的并行不是在模型上的并行,而是在特征上的并行,将特征列排序后以block的形式存储在内存中,在后面的迭代中重复使用这个结构。这个block也使得并行化成为了可能,其次在进行节点分裂时,计算每个特征的增益,最终选择增益最大的那个特征去做分割,那么各个特征的增益计算就可以开多线程进行。

猜你喜欢

转载自www.cnblogs.com/jiangxinyang/p/9248154.html