XGBOOST(待完善)

(黄色文本表示没有完全理解,待完善)

XGBOOST,全称eXtreme Gradient Boosting,是一种监督学习模型。给定输入X\in R^{d},预测Y

XGBOOST是GBDT(Gradient Boosted Decision Trees)的一种。是一个加性回归模型,通过 boosting 迭代的构造一组弱学习器,相对 LR 的优势如不需要做特征的归一化,自动进行特征选择,模型可解释性较好, 可以适应多种损失函数如 SquareLoss,LogLoss 等等。但作为非线性模型,其相 对线性模型的缺点也是显然的:boosting 是个串行的过程,不能并行化,计算复 杂度较高,同时其不太适合高维稀疏特征

首先来看一个小例子,希望能通过这个例子知道为什么要用XGBOOST。

憨憨和哈哈是形影不离的好朋友,一天,他们一起去山里摘苹果。按照计划,他们打算去摘山谷底部的那棵大苹果树。虽然哈哈聪明而富有冒险精神,而憨憨有些谨慎和迟钝,但他们中会爬树的只有憨憨。那么他们的路径是什么呢?

如上图所示,憨憨和哈哈所在的位置是a点,他们的目标苹果树位于g点。山里环境复杂,要怎么做才能确定自己到了山谷底部呢?他们有两种方法。

1.由哈哈计算“a”点的斜率,如果斜率为正,则继续朝这个方向前进;如果为负,朝反方向前进。

斜率给出了前进的方向,但没有说明他们需要朝这个方向移动多少。为此,韩梅梅决定走几步台阶,算一下斜率,确保自己不会到达错误位置,最终错过大苹果树。但是这种方法有风险,控制台阶多少的是学习率,这是个需要人为把控的值:如果学习率过大,憨憨和哈哈很可能会在g点两侧来回奔走;如果学习率过小,可能天黑了他们都未必摘得到苹果。

听到可能会走错路,憨憨不乐意了,他不想绕远路,也不愿意错过回家吃饭的时间。看到好友这么为难,哈哈提出了第二种方法。

2.在第一种方法的基础上,每走过特定数量的台阶,都由哈哈去计算每一个台阶的损失函数值,并从中找出局部最小值,以免错过全局最小值。每次哈哈找到局部最小值,她就发个信号,这样憨憨就永远不会走错路了。但这种方法对女孩子不公平,可怜的哈哈需要探索她附近的所有点并计算所有这些点的函数值。

XGBoost的优点在于它能同时解决以上两种方案的缺陷。

XGBOOST是一个加性回归模型,每一步提升的时候都会学习一个弱的学习器(弱学习器是高偏差,低方差的),也就是基学习器,也就是决策树(BGDT中的DT)。XGBOOST一般使用的都是回归树(为什么不选择分类树呢?前面提到XGBOOST是加性回归模型,试想下两个类别的相减,比如猫-狗?这根本不能减,所以选择的都是回归树。但XGBOOST也可以解决分类问题,只不过预测的值要经过softmax得到概率才能得到分类值,并不能直接分类)

如上式所示,最终得到的强学习器是由K个弱的学习器通过线性加和得到。

下面介绍具体的XGBOOST学习过程。首先是优化目标,也就是损失函数,如下所示

有训练损失和正则损失相加得到。正则损失代表的是模型的复杂度,一般有决策树的深度和叶子节点的个数等。

接下来看具体的学习过程。

如上图所示。boosting是一个串行的过程,每一轮会学习一个弱模型。假设现在执行到了第t轮。则

计算L损失的时候,要用到泰勒展开去逼近。传统的GBDT泰勒展开到1阶,是位1阶逼近,XGBOOST展开到二阶,是二阶逼近。

把常数项去掉之后,优化目标变为上式。

现在加入正则项的定义式。如下所示

将n个节点换个形式表达一下,假设当前待学习的树有T个叶子节点,则上式可变为

接下来的步骤就是枚举可能的树结构,寻找结构得分最优的结构,再对数的叶子节点赋值,但是这样枚举可能会有无穷个树结构。XGBOOST在这里运用了贪心的想法。具体如下

以年龄为例,举例如下所示

以上是只有两类的情况,原论文算法如下所示

根据特征划分有无数可能的树结构,因此采用近似算法(特征分位点,候选分割点) 

问题来了,怎么确定分割点呢? 较少的离散值作为分割点倒是很简单,比如“是否是单身”来分裂节点计算增益是很easy,但是“月收入”这种feature,取值很多,从5k~50k都有,总不可能每个分割点都来试一下计算分裂增益吧?(比如月收入feature有1000个取值,难道你把这1000个用作分割候选?缺点1:计算量,缺点2:出现叶子节点样本过少,过拟合)我们常用的习惯就是划分区间,作者是这么做的: 方法名字:Weighted Quantile Sketch 大家还记得每个样本在节点(将要分裂的节点)处的loss function一阶导数 gi  和二阶导数 hi ,衡量预测值变化带来的loss function变化,举例来说,将样本“月收入”进行升序排列,5k、5.2k、5.3k、…、52k,分割线为“收入1”、“收入2”、…、“收入j”,满足(每个间隔的样本的 hi 之和/总样本的 hi 之和)为某个百分比ϵ  (我这个是近似的说法),那么可以一共分成大约 1 / ϵ 个分裂点。

原论文中还有一种针对数据比较稀疏的算法,贴下来做个记号

最后是关于剪支和正则化的部分。

记得不知道哪位大佬说递归的剪支可以用动态规划的方法优化。打个记号,暂时没想明白!

XGBOOST和GBDT的比较

1.传统GBDT以CART作为基函数,但xgboost支持线性分类器(booster:gbtree、gblinear),这个时候xgboost相当于带L1和L2正则化项的逻辑斯蒂回归(分类问题)或者线性回归(回归问题)。 

2.传统GBDT在优化时只用到一阶导数信息,xgboost则对代价函数进行了二阶泰勒展开,同时用到了一阶和二阶导数(g一阶导数,h二阶导数)

3.xgboost在代价函数里加入了正则项,用于控制模型的复杂度。正则项里包含了树的叶子节点个数、叶子节点的权重的平方。从Bias-variance tradeoff角度来讲,正则项降低了模型variance,使学习出来的模型更加简单,防止过拟合,这也是xgboost优于传统GBDT的一个特性 。同时XGBOOST还支持自定义损失函数,只需要可以求二阶导就行。

4.shrinkage(步长) and column subsampling —还是为了防止过拟合
(1)shrinkage缩减类似于学习速率,在每一步tree boosting之后增加了一个参数n(权重),通过这种方式来减小每棵树的影响力,给后面的树提供空间去优化模型。
(2)column subsampling列(特征)抽样,说是从随机森林那边学习来的,防止过拟合的效果比传统的行抽样还好(行抽样功能也有),并且有利于并行化处理算法。

5.split finding algorithms(划分点查找算法):
(1)exact greedy algorithm—贪心算法获取最优切分点 (2)approximate algorithm— 近似算法,提出了候选分割点概念,先通过直方图算法获得候选分割点的分布情况,然后根据候选分割点将连续的特征信息映射到不同的buckets中,并统计汇总信息。

6.对缺失值的处理。对于特征的值有缺失的样本,xgboost可以自动学习出它的分裂方向。
 

下面对XGBOOST做下总结

1、XGBOOST支持并行。前面已经提到说XGBOOST是串行建树的,那为什么说支持并行呢?原因在于XGBOOST训练过程中,时间占比最大的是选择最佳分裂点,而不是串行建树的过程。而恰好选择最佳分裂点是可以并行计算的。

2、为了防止过拟合,引入了缩减因子和正则化项。

还有几点疑问,待解决。

1、为什么说XGBOOST每一步得到的弱学习器必须要高偏差,低方差

 


部分内容引用链接

1、http://www.javashuo.com/article/p-tqikcsnq-dk.html

2、陈天奇PPT Introduction to Boosted Trees

3、http://m.elecfans.com/article/736269.html

4、http://www.sohu.com/a/226265476_609569

5、XGBOOST原论文 https://arxiv.org/pdf/1603.02754.pdf