之前肝了三篇XGBoost
涉及到的起源
挂枝儿:从Boosting到BDT再到GBDTzhuanlan.zhihu.com到XGBoost的总体推到过程
挂枝儿:再从GBDT到XGBoost!zhuanlan.zhihu.com再到代码层面的参数初步理解
挂枝儿:XGBoost从原理到调参zhuanlan.zhihu.com现在基本能够大概讲清楚XGBoost到底是怎么一回事了,但是遇到具体的问题的时候对于XGBoost 到底怎么去兼顾分类和回归问题,其中有哪些区别感觉还是有些疑惑,我总结了一下,就是目前为止的对于算法的理解其实还缺了一个很大的部分,那就是:
形象的理解树 到底是怎么长的?
所以今天的这篇(应该是最后一篇了)就是想结合具体的案例,分别用XGBoost来进行回归和分类来彻底理解每棵树是怎么长的,个人过了一遍之后对于XGBoost正则化参数的理解感觉又比之前上了一个层次。
下面开始:
之前的原理篇有提到,XGBoost最厉害的地方是他是一个抽象的算法框架,无论我们是拿他来进行回归,我们都可以根据泰勒展开后的目标函数得到下式,下面简单再进行一下重新推导:
根据上式,我们需要最小化Ovalue,求导=0可得(<===重点1!!!)! !
再将求得的Ovalue最小值带回我们的目标函数,得到我们的叶子节点分数(<===重点2!!!)
注意到上式最后把1/2约去了,那是因为求最小值常量不碍事可直接约去
开始做分类与回归:
- 根据上面的式子我们可以发现,无论是做分类还是回归,为了分裂节点建树,我们都需要:
1. 把最小化叶子节点分数得到,为了得到最小化的叶子节点分数,我们需要计算损失函数对于叶子节点的一阶到二阶导
2. 计算Similarity Score
3. 计算子节点的Similarity Score,与父节点相减得到gain(需要最大化gain)
4. 重复以上...
5. 确定树结构后通过lambda,gamma进行剪枝(对应下图计算梯度和分裂节点的部分)
XGBoost的回归树
我们先从回归树说起(更简单一些)
对于回归问题,一般来说我们最常用的损失函数就是
一阶导gi (用到链式法则),可以理解为残差
二阶导hi (求没了已经) 全部为1
写到这里,我们可以惊喜的发现,对于回归问题,XGBoost的最优化叶子节点式子就可以写成:
分子就是残差,分母就是叶子节点的样本数量+lambda
相应的目标函数就可以写为:
分子就是残差和的平方,分母就是叶子节点的样本数量+lambda
接下来我们通过boston放假数据集来验证我们的想法,作为样例:
from
我们可以发现根节点的gain = 19339.546900
我们再通过手动计算一遍,看看手动的梯度计算,叶子节点的计算分数是否能和算法输出出来的数字一致:
full
可以发现我们的gain分数是完全对的上的!
刚刚为了方便计算,我们故意把lambda设成了0,这次我们设成1,再看看结果
train
full
可以发现第一棵树的数字被压缩了,这也正是正则化参数lambda存在的目的,其实从他在狮子中的位置也可以看得出来:lambda越大,节点少的叶子的权重会被稀释的越厉害,而叶子节点多的权重收到的影响会稍小一些。
用高深点的话说 :lambda>0时,会shrink我们的分数值,让输出的结果分更小。(我看到这里感觉有种他和学习率eta双重绑定,环环相扣的感觉)
在后剪枝的过程中,gamma会参与进来,所有分裂得分<gamma的叶子都会被砍去.
分类树:
接下来再来啃一下有点劝退的分类树:
分类函数的损失一般用logloss
我们把logloss转换一下(先放一个p,log_odds,odds解释图,看不懂的话可以先理解一图里的式子)
所以最终我们的损失函数的等于:
一阶导gi (依旧是残差,只不过是概率
二阶导hi (一个很奇妙的相互乘的式子)
得到了这两个式子后,我们就可以得到分类树的叶子节点最优分:
分子依旧是残差,分母是前一项预测值交叉乘 + lambda
以及对应的结构分
同样的,我们来用一个例子验证一下我们的式子
iris
full
可以发现也是对的上的。同时我们可以发现,xgboost中的一个minchildweight参数其实就是回归树中的分母的叶子数量,分类树中的概率交互乘项,可以发现在定义这个参数时分类与回归树的区别还是要注意,2个参数在不同的分类任务下的值域显然是不同的。
最后放一个分类回归分数计算和结果分数的式子对比,方便加深印象总结:
- 分类树 回归树所用的算法思想是一致的,都是在XGBOOST的框架下,不停的去拟合上一轮的残差(都是0.5分开始)
- 两者的损失函数不同造成两者生长的策略有所不同,导致XGBOOST 的参数像是minchildweight设置的值域也不同.