https://blog.csdn.net/xwd18280820053/article/details/68927422
决策树详见:https://blog.csdn.net/weixin_39910711/article/details/79468798
常用的决策树算法有ID3(信息增益),C4.5(信息增益比),CART(基尼指数)三种。3种算法的模型构建思想都十分类似,只是采用了不同的指标。决策树模型的构建过程大致如下:
输入:训练集D,特征集A,阈值eps 输出:决策树T
这里只简单介绍下CART与ID3和C4.5的区别。
事实上,分类与回归是一个型号的东西,只不过分类的结果是离散值,回归是连续的,本质是一样的,都是特征(feature)到结果/标签(label)之间的映射。说说决策树和回归树,在上面决策树的讲解中相信决策树分类已经很好理解了。
分类树的样本输出(即响应值)是类的形式,如判断蘑菇是有毒还是无毒,周末去看电影还是不去。
而回归树的样本输出是数值的形式,比如给某人发放房屋贷款的数额就是具体的数值,可以是0到120万元之间的任意值。那么,这时候你就没法用上述的信息增益、信息增益率、基尼系数来判定树的节点分裂了,你就会采用新的方式,预测误差,常用的有均方误差、对数误差等。而且节点不再是类别,是数值(预测值),那么怎么确定呢,有的是节点内样本均值,有的是最优化算出来的比如Xgboost。
决策树的剪枝主要是为了预防过拟合。
主要思路是从叶节点向上回溯,尝试对某个节点进行剪枝,比较剪枝前后的决策树的损失函数值。最后我们通过动态规划(树形dp)就可以得到全局最优的剪枝方案。
将决策树与集成学习框架进行结合所得到的新的算法:
1)Bagging + 决策树 = 随机森林(Random Forest)
2)AdaBoost + 决策树 = 提升树(Boosting Decision Tree)
3)Gradient Boosting + 决策树 = 梯度提升树(Gradient Boosting Decision Tree,GBDT)
GBDT(Gradient Boosting Decision Tree) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。它在被提出之初就和SVM一起被认为是泛化能力(generalization)较强的算法。
在目标函数所在的函数空间中做梯度下降,即把待求的函数模型当作参数,每一步要拟合目标函数关于上一步获得的模型的梯度,从而使得参数朝着最小化目标函数的方向更新。
GBDT(Gradient Boosting Decison Tree)中的树都是回归树,GBDT用来做回归预测,调整后也可以用于分类(设定阈值,大于阈值为正例,反之为负例),可以发现多种有区分性的特征以及特征组合。GBDT是把所有树的结论累加起来做最终结论的,GBDT的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。
Boosting的最大好处在于,每一步的残差计算其实变相地增大了分错instance的权重,而已经分对的instance则都趋向于0。这样后面的树就能越来越专注那些前面被分错的instance。Gradient Boost与传统的Boost的区别是,每一次的计算是为了减少上一次的残差(residual),而为了消除残差,我们可以在残差减少的梯度(Gradient)方向上建立一个新的模型。所以说,在Gradient Boost中,每个新的模型的建立是为了使模型的残差往梯度方向减少。Shrinkage(缩减)的思想认为,每次走一小步逐渐逼近结果的效果,要比每次迈一大步很快逼近结果的方式更容易避免过拟合。即它不完全信任每一个棵残差树,它认为每棵树只学到了真理的一小部分,累加的时候只累加一小部分,通过多学几棵树弥补不足。本质上,Shrinkage为每棵树设置了一个weight,累加时要乘以这个weight,但和Gradient并没有关系。
一些特性:
GBDT主要由三个概念组成:Regression Decistion Tree(即DT),Gradient Boosting(即GB),Shrinkage (算法的一个重要演进分枝,目前大部分源码都按该版本实现)。
提起决策树(DT, Decision Tree) ,千万不要以为GBDT是很多棵分类树。决策树分为两大类,回归树和分类树。前者用于预测实数值,如明天的温度、用户的年龄、网页的相关程度;后者用于分类标签值,如晴天/阴天/雾/雨、用户性别、网页是否是垃圾页面。这里要强调的是,前者的结果加减是有意义的,如10岁+5岁-3岁=12岁,后者则无意义,如男+男+女=到底是男是女? GBDT的核心在于累加所有树的结果作为最终结果,就像前面对年龄的累加(-3是加负3),而分类树的结果显然是没办法累加的,所以GBDT中的树都是回归树,不是分类树,这点对理解GBDT相当重要(尽管GBDT调整后也可用于分类但不代表GBDT的树是分类树)。那么回归树是如何工作的呢?
下面我们以对人的性别判别 / 年龄预测为例来说明,每个instance都是一个我们已知性别/年龄的人,而feature则包括这个人上网的时长、上网的时段、网购所花的金额等。
作为对比,先说分类树,C4.5分类树在每次分枝时,是穷举每一个feature的每一个阈值,找到使得按照feature<=阈值,和feature>阈值分成的两个分枝的熵最大的feature和阈值(熵最大的概念可理解成尽可能每个分枝的男女比例都远离1:1),按照该标准分枝得到两个新节点,用同样方法继续分枝直到所有人都被分入性别唯一的叶子节点,或达到预设的终止条件,若最终叶子节点中的性别不唯一,则以多数人的性别作为该叶子节点的性别。
回归树总体流程也是类似,不过在每个节点(不一定是叶子节点)都会得一个预测值,以年龄为例,该预测值等于属于这个节点的所有人年龄的平均值。分枝时穷举每一个feature的每个阈值找最好的分割点,但衡量最好的标准不再是最大熵,而是最小化均方差——即(每个人的年龄-预测年龄)^2 的总和 / N,或者说是每个人的预测误差平方和除以 N。这很好理解,被预测出错的人数越多,错的越离谱,均方差就越大,通过最小化均方差能够找到最靠谱的分枝依据。分枝直到每个叶子节点上人的年龄都唯一(这太难了)或者达到预设的终止条件(如叶子个数上限),若最终叶子节点上人的年龄不唯一,则以该节点上所有人的平均年龄做为该叶子节点的预测年龄。
Boosting,迭代,即通过迭代多棵树来共同决策。这怎么实现呢?难道是每棵树独立训练一遍,比如A这个人,第一棵树认为是10岁,第二棵树认为是0岁,第三棵树认为是20岁,我们就取平均值10岁做最终结论?--当然不是!且不说这是投票方法并不是GBDT,只要训练集不变,独立训练三次的三棵树必定完全相同,这样做完全没有意义。GBDT是把所有树的结论累加起来做最终结论的,所以可以想到每棵树的结论并不是年龄本身,而是年龄的一个累加量。GBDT的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。比如A的真实年龄是18岁,但第一棵树的预测年龄是12岁,差了6岁,即残差为6岁。那么在第二棵树里我们把A的年龄设为6岁去学习,如果第二棵树真的能把A分到6岁的叶子节点,那累加两棵树的结论就是A的真实年龄;如果第二棵树的结论是5岁,则A仍然存在1岁的残差,第三棵树里A的年龄就变成1岁,继续学。
还是年龄预测,简单起见训练集只有4个人,A,B,C,D,他们的年龄分别是14,16,24,26。其中A、B分别是高一和高三学生;C,D分别是应届毕业生和工作两年的员工。如果是用一棵传统的回归决策树来训练,会得到如下图1所示结果:
图1
现在我们使用GBDT来做这件事,由于数据太少,我们限定叶子节点最多有两个,即每棵树都只有一个分枝,并且限定只学两棵树。我们会得到如下图2所示结果:
图2
在第一棵树分枝和图1一样,由于A,B年龄较为相近,C,D年龄较为相近,他们被分为两拨,每拨用平均年龄作为预测值。此时计算残差(残差的意思就是: A的预测值 + A的残差 = A的实际值),所以A的残差就是16-15=1(注意,A的预测值是指前面所有树累加的和,这里前面只有一棵树所以直接是15,如果还有树则需要都累加起来作为A的预测值)。进而得到A,B,C,D的残差分别为-1,1,-1,1。然后我们拿残差替代A,B,C,D的原值,到第二棵树去学习,如果我们的预测值和它们的残差相等,则只需把第二棵树的结论累加到第一棵树上就能得到真实年龄了。这里的数据显然是我可以做的,第二棵树只有两个值1和-1,直接分成两个节点。此时所有人的残差都是0,即每个人都得到了真实的预测值。
换句话说,现在A,B,C,D的预测值都和真实年龄一致了:
那么哪里体现了Gradient呢?其实回到第一棵树结束时想一想,无论此时的cost function是什么,是均方差还是均差,只要它以误差作为衡量标准,残差向量(-1, 1, -1, 1)都是它的全局最优方向,这就是Gradient。
既然图1和图2 最终效果相同,为何还需要GBDT呢?
答案是过拟合。过拟合是指为了让训练集精度更高,学到了很多”仅在训练集上成立的规律“,导致换一个数据集当前规律就不适用了。其实只要允许一棵树的叶子节点足够多,训练集总是能训练到100%准确率的(大不了最后一个叶子上只有一个instance)。在训练精度和实际精度(或测试精度)之间,后者才是我们想要真正得到的。
我们发现图1为了达到100%精度使用了3个feature(上网时长、时段、网购金额),其中分枝“上网时长>1.1h” 很显然已经过拟合了,这个数据集上A,B也许恰好A每天上网1.09h, B上网1.05小时,但用上网时间是不是>1.1小时来判断所有人的年龄很显然是有悖常识的;
相对来说图2的boosting虽然用了两棵树 ,但其实只用了2个feature就搞定了,后一个feature是问答比例,显然图2的依据更靠谱。Boosting的最大好处在于,每一步的残差计算其实变相地增大了分错instance的权重,而已经分对的instance则都趋向于0。这样后面的树就能越来越专注那些前面被分错的instance。就像做互联网,总是先解决60%用户的需求凑合着,再解决35%用户的需求,最后才关注那5%人的需求,这样就能逐渐把产品做好,因为不同类型用户需求可能完全不同,需要分别独立分析。如果反过来做,或者刚上来就一定要做到尽善尽美,往往最终会竹篮打水一场空。
我们通过一张图片来说明gbdt的训练过程:
图 3:GBDT 的训练过程
gbdt通过多轮迭代,每轮迭代产生一个弱分类器,每个分类器在上一轮分类器的残差基础上进行训练。对弱分类器的要求一般是足够简单,并且是低方差和高偏差(模型的预测效果不好,但是模型比较健壮(稳定),预测结果比较集中)的。因为训练的过程是通过降低偏差来不断提高最终分类器的精度。
弱分类器一般会选择为CART TREE(也就是分类回归树)。由于上述高偏差和简单的要求,每个分类回归树的深度不会很深。最终的总分类器是将每轮训练得到的弱分类器加权求和得到的(也就是加法模型)。
在GBDT的迭代中,假设我们前一轮迭代得到的强学习器是, 损失函数是 ,我们本轮迭代的目标是找到一个CART回归树模型的弱学习器,让本轮的损失函数最小。也就是说,本轮迭代找到决策树,要让样本的损失尽量变得更小。
gbdt选择特征的细节其实是想问你CART Tree生成的过程。这里有一个前提,gbdt的弱分类器默认选择的是CART TREE。其实也可以选择其他弱分类器的,选择的前提是低方差和高偏差。框架服从 boosting 框架即可。
下面我们具体来说CART TREE(是一种二叉树) 如何生成。CART TREE 生成的过程其实就是一个选择特征的过程。假设我们目前总共有 M 个特征。第一步我们需要从中选择出一个特征 j,做为二叉树的第一个节点。然后对 特征 j 的值选择一个切分点 m。一个样本的特征j的值如果小于m,则分为一类;如果大于m,则分为另外一类,如此便构建了CART 树的一个节点。其他节点的生成过程和这个是一样的。现在的问题是在每轮迭代的时候,如何选择这个特征 j,以及如何选择特征 j 的切分点 m:
原始的gbdt的做法非常的暴力,首先遍历每个特征,然后对每个特征遍历它所有可能的切分点,找到最优特征 m 的最优切分点 j。我们先遍历训练样本的所有的特征,对于特征 j,我们遍历特征 j 所有特征值的切分点 c。找到可以让下面这个式子最小的特征 j 以及切分点c。
其实说gbdt 能够构建特征并非很准确,gbdt 本身是不能产生特征的,但是我们可以利用gbdt去产生特征的组合。在CTR预估中,工业界一般会采用逻辑回归去进行处理,逻辑回归本身是适合处理线性可分的数据,如果我们想让逻辑回归处理非线性的数据,其中一种方式便是组合不同特征,增强逻辑回归对非线性分布的拟合能力。
长久以来,我们都是通过人工的先验知识或者实验来获得有效的组合特征,但是很多时候,使用人工经验知识来组合特征过于耗费人力,造成了机器学习当中一个很奇特的现象:有多少人工就有多少智能。关键是这样通过人工去组合特征并不一定能够提升模型的效果。所以我们的从业者或者学界一直都有一个趋势便是通过算法自动,高效的寻找到有效的特征组合。Facebook 在2014年 发表的一篇论文便是这种尝试下的产物,利用gbdt去产生有效的特征组合,以便用于逻辑回归的训练,提升模型最终的效果。
图 4:用GBDT 构造特征
如图 4 所示,我们使用 GBDT 生成了两棵树,两颗树一共有五个叶子节点。我们将样本 X 输入到两颗树当中去,样本X 落在了第一棵树的第二个叶子节点,第二颗树的第一个叶子节点,于是我们便可以依次构建一个五纬的特征向量,每一个纬度代表了一个叶子节点,样本落在这个叶子节点上面的话那么值为1,没有落在该叶子节点的话,那么值为 0.
于是对于该样本,我们可以得到一个向量[0,1,0,1,0] 作为该样本的组合特征,和原来的特征一起输入到逻辑回归当中进行训练。实验证明这样会得到比较显著的效果提升。
为解决损失函数拟合方法的问题,大牛Freidman提出了用损失函数的负梯度来拟合本轮损失的近似值,进而拟合一个CART回归树。第t轮的第i个样本的损失函数的负梯度:
利用,我们可以拟合一颗CART回归树,得到了第t颗回归树,其对应的叶节点区域。其中J为叶子节点的个数。
针对每一个叶子节点里的样本,我们求出使损失函数最小,也就是拟合叶子节点最好的的输出值j如下:
这样我们就得到了本轮的决策树拟合函数如下:
从而本轮最终得到的强学习器的表达式如下:
gbdt 通过经验风险极小化来确定下一个弱分类器的参数。具体到损失函数本身的选择也就是L的选择,有平方损失函数,0-1损失函数,对数损失函数等等。如果我们选择平方损失函数,那么这个差值其实就是我们平常所说的残差。这样每轮训练的时候都能够让损失函数尽可能快的减小,尽快的收敛达到局部最优解或者全局最优解。
通过损失函数的负梯度来拟合,我们找到了一种通用的拟合损失误差的办法,这样无论是分类问题还是回归问题,我们通过其损失函数的负梯度的拟合,就可以用GBDT来解决我们的分类回归问题。区别仅仅在于损失函数不同导致的负梯度不同而已。
输入:训练集样本, 最大迭代次数T,损失函数L。
输出:是强学习器f(x)
1) 初始化弱学习器
2) 对迭代轮数 t =1,2,...T 有:
a) 对样本i=1,2,...m,计算负梯度
b) 利用 ,拟合一颗CART回归树,得到第 t 颗回归树,其对应的叶子节点区域为。其中J为回归树t的叶子节点的个数。
c) 对叶子区域 j =1,2,..J,计算最佳拟合值
d) 更新强学习器
3) 得到强学习器f(x)的表达式
GBDT的分类算法从思想上和GBDT的回归算法没有区别,但是由于样本输出不是连续的值,而是离散的类别,导致我们无法直接从输出类别去拟合类别输出的误差。
为了解决这个问题,主要有两个方法,一个是用指数损失函数,此时GBDT退化为Adaboost算法。另一种方法是用类似于逻辑回归的对数似然损失函数的方法。也就是说,我们用的是类别的预测概率值和真实概率值的差来拟合损失。本文仅讨论用对数似然损失函数的GBDT分类。而对于对数似然损失函数,我们又有二元分类和多元分类的区别。
首先明确一点,gbdt 无论用于分类还是回归一直都是使用的 CART 回归树。不会因为我们所选择的任务是分类任务就选用分类树,这里面的核心是因为gbdt 每轮的训练是在上一轮的训练的残差基础之上进行训练的。这里的残差就是当前模型的负梯度值 。这个要求每轮迭代的时候,弱分类器的输出的结果相减是有意义的,残差相减是有意义的。
如果选用的弱分类器是分类树,类别相减是没有意义的。上一轮输出的是样本 x 属于 A类,本一轮训练输出的是样本 x 属于 B类。 A 和 B 很多时候甚至都没有比较的意义,A 类- B类是没有意义的。
对于二元GBDT,如果用类似于逻辑回归的对数似然损失函数,则损失函数为:
其中。则此时的负梯度误差为
对于生成的决策树,我们各个叶子节点的最佳负梯度拟合值为
由于上式比较难优化,我们一般使用近似值代替
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,二元GBDT分类和GBDT回归算法过程相同。
多元GBDT要比二元GBDT复杂一些,对应的是多元逻辑回归和二元逻辑回归的复杂度差别。假设类别数为K,则此时我们的对数似然损失函数为:
其中如果样本输出类别为k,则。第k类的概率的表达式为:
集合上两式,我们可以计算出第t轮的第i个样本对应类别l的负梯度误差为
观察上式可以看出,其实这里的误差就是样本i 对应类别l 的真实概率和 t−1轮预测概率的差值。
对于生成的决策树,我们各个叶子节点的最佳负梯度拟合值为
由于上式比较难优化,我们一般使用近似值代替
除了负梯度计算和叶子节点的最佳负梯度拟合的线性搜索,多元GBDT分类和二元GBDT分类以及GBDT回归算法过程相同。
多元GBDT分类算法:
假设样本 X 总共有 K类。来了一个样本 x,我们需要使用gbdt来判断 x 属于样本的哪一类。
图5 gbdt 多分类算法流程
第一步 我们在训练的时候,是针对样本 X 每个可能的类都训练一个分类回归树。举例说明,针对样本有三类的情况,我们实质上是在每轮的训练的时候是同时训练三颗树。目前样本有三类,也就是 K = 3。样本 x 属于 第二类。那么针对该样本 x 的分类结果,其实我们可以用一个 三维向量 [0,1,0] 来表示。0表示样本不属于该类,1表示样本属于该类。由于样本已经属于第二类了,所以第二类对应的向量维度为1,其他位置为0。第一颗树针对样本x的第一类,输入为(x,0)。第二颗树输入针对 样本x 的第二类,输入为(x,1)。第三颗树针对样本x 的第三类,输入为(x,0)。
在这里每颗树的训练过程其实就是我们之前已经提到过的CATR TREE 的生成过程。在此处我们参照之前的生成树的程序,即可以就解出三颗树,以及三颗树对x 类别的预测值。那么在此类训练中,我们仿照多分类的逻辑回归 ,使用softmax 来产生概率,则属于类别 1 的概率
并且我们可以针对类别1求出残差;类别2求出残差;类别3 求出残差。
然后开始第二轮训练,针对第一类输入为, 针对第二类输入为 ,针对 第三类输入为 .,继续训练出三颗树。一直迭代M轮。每轮构建 3颗树。
所以当K =3。我们其实应该有三个式子
当训练完毕以后,新来一个样本 x1 ,我们需要预测该样本的类别的时候,便可以有这三个式子产生三个值,。样本属于 某个类别c的概率为
上面的理论阐述可能仍旧过于难懂,我们下面将拿Iris 数据集中的六个数据作为例子,来展示gbdt 多分类的过程。
图6 Iris 数据集
这是一个有6个样本的三分类问题。我们需要根据这个花的花萼长度,花萼宽度,花瓣长度,花瓣宽度来判断这个花属于山鸢尾,杂色鸢尾,还是维吉尼亚鸢尾。具体应用到gbdt多分类算法上面。我们用一个三维向量来标志样本的label。[1,0,0] 表示样本属于山鸢尾,[0,1,0] 表示样本属于杂色鸢尾,[0,0,1] 表示属于维吉尼亚鸢尾。
gbdt 的多分类是针对每个类都独立训练一个 CART Tree。所以这里,我们将针对山鸢尾类别训练一个 CART Tree 1。杂色鸢尾训练一个 CART Tree 2 。维吉尼亚鸢尾训练一个CART Tree 3,这三个树相互独立。
我们以样本 1 为例。针对 CART Tree1 的训练样本是[5.1,3.5,1.4,0.2],label 是 1,最终输入到模型当中的为[5.1,3.5,1.4,0.2,1];针对 CART Tree2 的训练样本也是[5.1,3.5,1.4,0.2],但是label 为 0,最终输入模型的为[5.1,3.5,1.4,0.2,0]。 针对 CART Tree 3的训练样本也是[5.1,3.5,1.4,0.2],label 也为0,最终输入模型当中的为[5.1,3.5,1.4,0.2,0]。
下面我们来看 CART Tree1 是如何生成的,其他树 CART Tree2 , CART Tree 3的生成方式是一样的。CART Tree的生成过程是从这四个特征中找一个特征做为CART Tree1 的节点。比如花萼长度做为节点。6个样本当中花萼长度大于5.1 cm的就是 A类,小于等于5.1 cm 的是B类。生成的过程其实非常简单,问题 1.是哪个特征最合适? 2.是这个特征的什么特征值作为切分点? 即使我们已经确定了花萼长度做为节点。花萼长度本身也有很多值。在这里我们的方式是遍历所有的可能性,找到一个最好的特征和它对应的最优特征值可以让当前式子的值最小。
我们以第一个特征的第一个特征值为例。R1 为所有样本中花萼长度小于 5.1 cm 的样本集合,R2 为所有样本当中花萼长度大于等于 5.1cm 的样本集合。所以 R1={2},R2={1,3,4,5,6}。
y1 为 R1 所有样本的label 的均值 1/1=1。y2 为 R2 所有样本的label 的均值 (1+0+0+0+0)/5=0.2。
下面便开始针对所有的样本计算这个式子的值。样本1 属于 R2 计算的值为, 样本2 属于R1 计算的值为, 样本 3,4,5,6同理都是属于 R2的,所以值是, 把这六个值加起来,便是 山鸢尾类型在特征1 的第一个特征值的损失值。这里算出来(1-0.2)^2+ (1-1)^2 + (0-0.2)^2+(0-0.2)^2+(0-0.2)^2 +(0-0.2)^2= 0.84
我们可以遍历所有特征的所有特征值,找到让这个式子最小的特征以及其对应的特征值,一共有24种情况,4个特征*每个特征有6个特征值。在这里我们算出来让这个式子最小的特征花萼长度,特征值为5.1 cm。这个时候损失函数最小为 0.8。
于是我们的预测函数此时也可以得到:
此处 R1 = {2},R2 = {1,3,4,5,6},y1 = 1,y2 = 0.2。训练完以后的最终式子为
借由这个式子,我们得到对样本属于类别1 的预测值 f1(x)=1+0.2∗5=2。同理我们可以得到对样本属于类别2,3的预测值f2(x),f2(x),样本属于类别1的概率,即为
对于分类算法,其损失函数一般有对数损失函数和指数损失函数两种:
对于分类算法,其损失函数一般有对数损失函数和指数损失函数两种:
a) 如果是指数损失函数,则损失函数表达式为
b) 如果是对数损失函数,分为二元分类和多元分类两种,参见2.5.1节和2.5.2节。
a) 均方差,这个是最常见的回归损失函数了
b) 绝对损失,这个损失函数也很常见
对应负梯度误差为:
c) Huber损失,它是均方差和绝对损失的折衷产物,对于远离中心的异常点,采用绝对损失,而中心附近的点采用均方差。这个界限一般用分位数点度量。损失函数如下:
对应的负梯度误差为:
d) 分位数损失。它对应的是分位数回归的损失函数,表达式为
其中θ为分位数,需要我们在回归前指定。对应的负梯度误差为:
对于Huber损失和分位数损失,主要用于健壮回归,也就是减少异常点对损失函数的影响。
和Adaboost一样,我们也需要对GBDT进行正则化,防止过拟合。GBDT的正则化主要有三种方式。
第一种是和Adaboost类似的正则化项,即步长(learning rate)。定义为ν,对于前面的弱学习器的迭代
如果我们加上了正则化项,则有
ν的取值范围为0<ν≤1。对于同样的训练集学习效果,较小的ν意味着我们需要更多的弱学习器的迭代次数。通常我们用步长和迭代最大次数一起来决定算法的拟合效果。
第二种正则化的方式是通过子采样比例(subsample)。取值为(0,1]。注意这里的子采样和随机森林不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则全部样本都使用,等于没有使用子采样。如果取值小于1,则只有一部分样本会去做GBDT的决策树拟合。选择小于1的比例可以减少方差,即防止过拟合,但是会增加样本拟合的偏差,因此取值不能太低。推荐在[0.5, 0.8]之间。
使用了子采样的GBDT有时也称作随机梯度提升树(Stochastic Gradient Boosting Tree, SGBT)。由于使用了子采样,程序可以通过采样分发到不同的任务去做boosting的迭代过程,最后形成新树,从而减少弱学习器难以并行学习的弱点。
对于弱学习器即CART回归树进行正则化剪枝。
GDBT本身并不复杂,不过要吃透的话需要对集成学习的原理,决策树原理和各种损失函树有一定的了解。由于GBDT的卓越性能,只要是研究机器学习都应该掌握这个算法,包括背后的原理和应用调参方法。目前GBDT的算法比较好的库是xgboost。scikit-learn也可以。
最后总结下GBDT的优缺点。
GBDT主要的优点有:
1) 可以灵活处理各种类型的数据,包括连续值和离散值。
2) 在相对少的调参时间情况下,预测的准确率也可以比较高。这个是相对SVM来说的。
3) 使用一些健壮的损失函数,对异常值的鲁棒性非常强。比如 Huber损失函数和Quantile损失函数。
GBDT的主要缺点有:
1) 由于弱学习器之间存在依赖关系,难以并行训练数据。不过可以通过自采样的SGBT来达到部分并行。
XGBoost的进化史:
XGBoost全名叫(eXtreme Gradient Boosting)极端梯度提升,经常被用在一些比赛中,其效果显著。它是大规模并行boosted tree的工具,它是目前最快最好的开源boosted tree工具包。XGBoost 所应用的算法就是 GBDT(gradient boosting decision tree)的改进,既可以用于分类也可以用于回归问题中。与GBDT最大的区别是xgboost通过对目标函数做二阶泰勒展开,从而求出下一步要拟合的树的叶子节点权重(需要先确定树的结构),从而根据损失函数求出每一次分裂节点的损失减小的大小,从而根据分裂损失选择合适的属性进行分裂。
这个利用二阶展开得到的损失函数公式与分裂节点的过程是息息相关的。先遍历所有节点的所有属性进行分裂,假设选择了这个a属性的一个取值作为分裂节点,根据泰勒展开求得的公式可计算该树结构各个叶子节点的权重,从而计算损失减小的程度,从而综合各个属性选择使得损失减小最大的那个特征作为当前节点的分裂属性。依次类推,直到满足终止条件。
首先明确下我们的目标,希望建立K个回归树,使得树群的预测值尽量接近真实值(准确率)而且有尽量大的泛化能力(更为本质的东西),从数学角度看这是一个泛函最优化,多目标,看下目标函数:
其中i表示第i个样本,表示第i个样本的预测误差,误差越小越好,不然你算得上预测么?后面表示树的复杂度的函数,越小复杂度越低,泛化能力越强,这意味着啥不用我多说。表达式为
直观上看,目标要求预测误差尽量小,叶子节点尽量少,节点数值尽量不极端(这个怎么看,如果某个样本label数值为4,那么第一个回归树预测3,第二个预测为1;另外一组回归树,一个预测2,一个预测2,那么倾向后一种,为什么呢?前一种情况,第一棵树学的太多,太接近4,也就意味着有较大的过拟合的风险)
怎么实现呢?上面这个目标函数跟实际的参数怎么联系起来,记得我们说过,回归树的参数:(1)选取哪个feature分裂节点呢;(2)节点的预测值。上述形而上的公式并没有“直接”解决这两个,那么是如何间接解决的呢?
先说答案:贪心策略+最优化(二次最优化)
通俗解释贪心策略:就是决策时刻按照当前目标最优化决定,说白了就是眼前利益最大化决定,“目光短浅”策略,他的优缺点细节大家自己去了解,经典背包问题等等。
这里是怎么用贪心策略的呢,刚开始你有一群样本,放在第一个节点,这时候T=1,w多少呢,是求出来的,这时候所有样本的预测值都是w(这个地方自己好好理解,决策树的节点表示类别,回归树的节点表示预测值),带入样本的label数值,此时loss function变为
如果这里的l(w−yi)误差表示用的是平方误差,那么上述函数就是一个关于w的二次函数求最小值,取最小值的点就是这个节点的预测值,最小的函数值为最小损失函数。
这里处理的就是二次函数最优化!
要是损失函数不是二次函数咋办,使用泰勒展开式,不是二次的想办法近似为二次。
接着来,接下来要选个feature分裂成两个节点,变成一棵弱小的树苗,那么需要:(1)确定分裂用的feature,how?最简单的是粗暴的枚举,选择loss function效果最好的那个(关于粗暴枚举,Xgboost的改良并行方式咱们后面看);(2)如何确立节点的w以及最小的loss function?即二次函数的求最值(细节的会注意到,计算二次最值是不是有固定套路,导数=0的点)
那么节奏是,选择一个feature分裂,计算loss function最小值,然后再选一个feature分裂,又得到一个loss function最小值…你枚举完,找一个效果最好的,把树给分裂,就得到了小树苗。在分裂的时候,你可以注意到,每次节点分裂,loss function被影响的只有这个节点的样本,因而每次分裂,计算分裂的增益(loss function的降低量)只需要关注打算分裂的那个节点的样本。
接下来,继续分裂,按照上述的方式,形成一棵树,再形成一棵树,每次在上一次的预测基础上取最优进一步分裂/建树。
凡是这种循环迭代的方式必定有停止条件:
(1)当引入的分裂带来的增益小于一个阀值的时候,我们可以剪掉这个分裂,所以并不是每一次分裂loss function整体都会增加的,有点预剪枝的意思,阈值参数为 γ 正则项里叶子节点数 T 的系数;
(2)当树达到最大深度时则停止建立决策树,设置一个超参数max_depth,这个好理解吧,树太深很容易出现的情况学习局部样本,过拟合;
(3)当样本权重和小于设定阈值时则停止建树,这个解释一下,涉及到一个超参数-最小的样本权重和min_child_weight,和GBM的 min_child_leaf 参数类似,但不完全一样,大意就是一个叶子节点样本太少了,也终止同样是过拟合;
(4)貌似看到过有树的最大数量的
那节点分裂的时候是按照哪个顺序来的,比如第一次分裂后有两个叶子节点,先裂哪一个?答:同一层级的(多机)并行,确立如何分裂或者不分裂成为叶子节点 。
上面一部分我们知道了集成学习方法的预测模型,因为XGBoost也是集成学习方法的一种。对于XGBoost的预测模型同样可以表示为:
其中为树的总个数,表示第颗树,表示样本的预测结果。
其中损失函数也同样表示为:
其中为样本的训练误差,表示第棵树的正则项。
看到了这里,我们可能会想到,现在知道了模型预测函数和损失函数,那我们是不是直接就能求出其预测模型了呢?答案肯定不是,我们首先需要明确知道优化和求解的参数是什么呢?由上面的预测模型中,我们可以看到对于每棵树的预测值是如何计算的?想到这里,你就已经知道了需要做的事了,我需要求解和优化的就是每个叶子节点的得分值,也就是的值。另外我们知道XGBoost是以CART树中的回归树作为基分类器,在给定训练数据后,其单个树的结构(叶子节点个数、树深度等等)基本可以确定了。但XGBoost并不是简单重复的将几个CART树进行组合。它是一种加法模型,将模型上次预测(由t-1棵树组合而成的模型)产生的误差作为参考进行下一棵树(第t棵树)的建立。以此,每加入一棵树,将其损失函数不断降低。如下图就为加法模型案例,它将模型预测值与实际值残差作为下一颗树的输入数据。
对于加法策略可以表示如下:
初始化(模型中没有树时,其预测结果为0):
往模型中加入第一棵树:
往模型中加入第二棵树:
……
往模型中加入第t棵树:
其中表示第棵树,表示组合棵树模型对样本的预测结果。
我们知道,每次往模型中加入一棵树,其损失函数便会发生变化。另外在加入第 t 棵树时,则前面第 t-1 棵树已经训练完成,此时前面 t-1 棵树的正则项和训练误差都成已知常数项。对于每棵树的正则项部分,我们将在后面再细说。
如果损失函数采用均方误差时,其目标损失函数变为:
另外对于目标损失函数中的正则项(复杂度)部分,我们从单一的树来考虑。对于其中每一棵回归树,其模型可以写成:
其中为叶子节点的得分值,表示样本对应的叶子节点。为该树的叶子节点个数。
因此,在这里。我们将该树的复杂度写成:
复杂度计算例子如下:
此时,对于XGBoost的目标函数我们可以写为:
现在我们只需要找到f(t)来优化上式目标。
在推导之前,我们先介绍下泰勒展开式:
这里我们用泰勒展开式来近似原来的目标函数,将看作。则原目标函数可以写成:
令,,同时对于第t棵树时,为常数。同时去除所有常数项。故目标损失函数可以写成:
由上面介绍书的复杂度时,我们知道:,同时我们将目标函数全部转换成在第t棵树叶子节点的形式。因为目前对于可以看做是每个样本在第t棵树的叶子节点得分值相关函数的结果之和,所以我们也能从第t棵树的叶子节点上来表示。
上式中,前两行 i=1~n 求和为在样本中遍历,后两行 j = 1~T求和为在叶子节点上遍历,其中为第t棵树中总叶子节点的个数,表示在第个叶子节点上的样本,为第个叶子节点的得分值。
在这里,令,。
则:
对求偏导,并使其导函数等于0,则有:
求解得:
其目标函数可以为:
根据目标函数,如何分裂样本数据呢?
(1)w是最优化求出来的,不是啥平均值或规则指定的,这个算是一个思路上的新颖吧;
(2)正则化防止过拟合的技术,loss function里面就有;
(3)支持自定义loss function,只要能泰勒展开(能求一阶导和二阶导)就行;
(4)支持并行化,这是xgboost的闪光点,直接的效果是训练速度快。xgboost在实现上支持并行化,这里的并行化并不是类似于rf那样树与树之间的并行化,xgboost同boosting方法一样,在树的粒度上是串行的,但是在构建树的过程中,也就是在选择最佳分裂点,进行枚举的时候并行,比如同时计算多个属性的多个取值作为分裂特征及其值,然后,选择收益最大的特征及其取值对节点分裂。(据说恰好这个也是树形成最耗时的阶段)。
Attention:同层级节点可并行。具体的对于某个节点,节点内选择最佳分裂点,候选分裂点计算增益用多线程并行。
较少的离散值作为分割点倒是很简单,比如“是否是单身”来分裂节点计算增益是很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/ϵ个分裂点。
(5)XGBoost还特别设计了针对稀疏数据的算法
假设样本的第i个特征缺失时,无法利用该特征对样本进行划分,xgboost添加了对稀疏数据的支持,在计算分裂收益的时候只利用没有missing值的那些样本,但是在推理的时候,也就是在确定了树的结构,需要将样本映射到叶子节点的时候,需要对含有缺失值的样本进行划分,xgboost分别假设该样本属于左子树和右子树,比较两者分裂增益,选择增益较大的那一边作为该样本的分裂方向。
算法的主要思想是,分别假设特征缺失的样本属于右子树和左子树,而且只在不缺失的样本上迭代,分别计算缺失样本属于右子树和左子树的增益,选择增益最大的方向为缺失数据的默认方向(咋一看如果缺失情况为3个样本,那么划分的组合方式岂不是有8种?指数级可能性啊,仔细一看,应该是在不缺失样本情况下分裂后,把第一个缺失样本放左边计算下loss function和放右边进行比较,同样对付第二个、第三个…缺失样本,这么看来又是可以并行的?)(答:论文中“枚举”指的不是枚举每个缺失样本在左边还是在右边,而是枚举缺失样本整体在左边,还是在右边两种情况。 分裂点还是只评估特征不缺失的样本。);
(6)可实现后剪枝
(7)交叉验证,方便选择最好的参数,early stop,比如你发现30棵树预测已经很好了,不用进一步学习残差了,那么停止建树。
(8)行采样、列采样,随机森林的套路(防止过拟合)
(9)Shrinkage,你可以是几个回归树的叶子节点之和为预测值,也可以是加权,比如第一棵树预测值为3.3,label为4.0,第二棵树才学0.7,….再后面的树还学个鬼,所以给他打个折扣,比如3折,那么第二棵树训练的残差为4.0-3.3*0.3=3.01,这就可以发挥了啦,以此类推,作用是啥,防止过拟合,如果对于“伪残差”学习,那更像梯度下降里面的学习率;
(10)xgboost还支持设置样本权重,这个权重体现在梯度g和二阶梯度h上,是不是有点adaboost的意思,重点关注某些样本;
(11)xgboost 在实现时,需要将所有数据导入内存,做一次pre-sort(exact algorithm),这样在选择分裂节点时比较迅速;
(12)类似于随机森林,XGBoost在构建树的过程中,对每棵树随机选择一些属性作为分裂属性。
分裂算法有两种,一种是精确的分裂,一种是近似分裂算法。精确分裂算法就是把每个属性的每个取值都当作一次阈值进行遍历,采用的决策树是CART。近似分裂算法是对每个属性的所有取值进行分桶,按照各个桶之间的值作为划分阈值。xgboost提出了一个特殊的分桶策略,一般的分桶策略是每个样本的权重都是相同的,但是xgboost使每个样本的权重为损失函数在该样本点的二阶导(泰勒展开不应该是损失函数关于模型的展开吗?为什么会有在该样本点的二阶导这种说法? 因为模型是对所有样本点都通用的,把该样本输入到二阶导公式中就可以得到了)。
(13)除了类似于GBDT的缩减系数外,xgboost对每棵树的叶子节点个数和权重都做了惩罚,避免过拟合。
Xgboost第一感觉就是防止过拟合+各种支持分布式/并行,所以一般传言这种大杀器效果好(集成学习的高配)+训练效率高(分布式),与深度学习相比,对样本量和特征数据类型要求没那么苛刻,适用范围广。
说下GBDT:有两种描述版本,把GBDT说成一个迭代残差树,认为每一棵迭代树都在学习前N-1棵树的残差;把GBDT说成一个梯度迭代树,使用梯度迭代下降法求解,认为每一棵迭代树都在学习前N-1棵树的梯度下降值。有说法说前者是后者在loss function为平方误差下的特殊情况。仍然举个例子:第一棵树形成之后,有预测值ŷ i,真实值(label)为yi,前者版本表示下一棵回归树根据样本(xi,yi−ŷ i)进行学习,后者的意思是计算loss function在第一棵树预测值附近的梯度负值作为新的label,也就是对应xgboost中的−gi。
Xgboost和深度学习的关系,陈天奇在Quora上的解答如下:
不同的机器学习模型适用于不同类型的任务。深度神经网络通过对时空位置建模,能够很好地捕获图像、语音、文本等高维数据。而基于树模型的XGBoost则能很好地处理表格数据,同时还拥有一些深度神经网络所没有的特性(如:模型的可解释性、输入数据的不变性、更易于调参等)。
这两类模型都很重要,并广泛用于数据科学竞赛和工业界。举例来说,几乎所有采用机器学习技术的公司都在使用tree boosting,同时XGBoost已经给业界带来了很大的影响。
LigthGBM是boosting集合模型中的新进成员,由微软提供,它和XGBoost一样是对GBDT的高效实现,原理上它和GBDT及XGBoost类似,都采用损失函数的负梯度作为当前决策树的残差近似值,去拟合新的决策树。
4.1 提出LightGBM的动机
4.2 LightGBM在哪些地方进行了优化?
4.2.1 histogram算法
4.2.2 直方图差加速
4.2.3 决策树生长策略
4.2.4 直接支持类别特征
4.2.5 直接支持高效并行
4.2.6 网络通信优化
4.3 LightGBM原理
4.3.1 单边梯度采样,Gradient-based One-Side Sampling(GOSS)
4.3.2 互斥特征绑定,Exclusive Feature Bundling(EFB)
机器学习算法之LightGBM:https://www.biaodianfu.com/lightgbm.html
Lightgbm基本原理介绍:https://blog.csdn.net/qq_24519677/article/details/82811215
LightGBM 中文文档:https://lightgbm.apachecn.org/#/docs/7
基于决策树算法的分布式梯度提升框架。
1.LightGBM采用leaf-wise生长策略,每次从当前所有叶子中找到分裂增益最大(一般也是数据量最大)的一个叶子,然后分裂,如此循环;但会生长出比较深的决策树,产生过拟合(因此 LightGBM 在leaf-wise之上增加了一个最大深度的限制,在保证高效率的同时防止过拟合)。
2.LightGBM使用的是histogram算法,占用的内存更低,数据分隔的复杂度更低。比较巧妙的优化是 histogram 做差加速。一个容易观察到的现象:一个叶子的直方图可以由它的父亲节点的直方图与它兄弟的直方图做差得到。
下面是将决策树与这些算法框架进行结合所得到的新的算法:
1)Bagging + 决策树 = 随机森林(Random Forest)
2)AdaBoost + 决策树 = 提升树(Boosting Decision Tree)
3)Gradient Boosting + 决策树 = 梯度提升树(Gradient Boosting Decision Tree,GBDT)
随机森林是一种重要的基于Bagging的集成学习方法,可以用来做分类、回归等问题。
随机森林有许多优点:
随机森林的缺点:
与上面介绍的Bagging过程相似,随机森林的构建过程大致如下:
GBDT:
梯度提升树(GBDT)原理小结:https://www.cnblogs.com/pinard/p/6140514.html
一文弄懂AdaBoost、提升树、残差树、GDBT:https://zhuanlan.zhihu.com/p/59751960
机器学习算法GBDT的面试要点总结-上篇:https://www.cnblogs.com/ModifyRong/p/7744987.html
机器学习与人工智能技术分享(未完待续):https://www.zybuluo.com/vivounicorn/note/446479#4210-adam
https://blog.csdn.net/dujiahei/article/details/86695004
http://statweb.stanford.edu/~jhf/ftp/trebst.pdf
Boosting Decision Tree入门教程 http://www.schonlau.net/publication/05stata_boosting.pdf
LambdaMART用于搜索排序入门教程 http://research.microsoft.com/pubs/132652/MSR-TR-2010-82.pdf
XGBoost:
Introduction to Boosted Trees:https://xgboost.readthedocs.io/en/latest/tutorials/model.html
xgboost原理:https://www.zhihu.com/question/58883125/answer/554373500
Python机器学习笔记:XgBoost算法:https://www.cnblogs.com/wj-1314/p/9402324.html
机器学习--boosting家族之XGBoost算法:https://www.cnblogs.com/zongfa/p/9324684.html