XGBoost笔记

GBDT(Gradient Boost Decision Tree)

首先介绍下XGBoost的前身,gbdt

损失函数

gbdt的损失函数为:

\[Loss_t = \frac{1}{n}\sum\nolimits^{n}_{i=1}{l(y_i, \hat{y}_i^{(t)})}, \qquad \hat{y}_i^{(t)} = \sum\nolimits_{k=1}^{t}{f_{k}(x_{i})} \]

每轮迭代时,损失函数为:

\[Loss = \frac{1}{n}\sum\nolimits^{n}_{i=1}{l(y_i, \hat{y}_i^{(t-1)} + f_t(x_i))}, \quad \hat{y}_i^{(t-1)} = \sum\nolimits_{k=1}^{t-1}{f_{k}(x_{i})} \]

Loss=MSE时拟合残差

当损失函数为MSE(均方误差)时,Loss变为:

\[\begin{align} Loss &= \frac{1}{n}\sum_{i=1}^{n}{[y_i-({\hat{y}}_i^{(t-1)}+f_t(x_i))]^2} \\ &= \frac{1}{n}\sum_{i=1}^{n}{[(y_i-{\hat{y}}_i^{(t-1)})-f_t(x_i)]^2} \end{align} \]

要使得此时得Loss最小,即让当前树\(f_t(x_i)\)尽量拟合\((y_i-{\hat{y}}_i^{(t-1)})\),即上一轮模型的残差

不为MSE时拟合负梯度

当函数不为MSE时,需要用一阶泰勒展开求取当前树的拟合目标

泰勒公式:一个用函数在某点的信息描述其附近取值的公式

在GBDT中即使用Loss函数在上一轮的预测值上的信息来描述本轮的预测值。GBDT使用了上一轮的Loss值、一阶导;xgb则还用到了二阶导。

一阶泰勒展开如下

\[f(x){\approx}f(x_0)+f'(x_0)(x-x_0)\\ f(x_0+{\Delta}x){\approx}f(x_0)+f'(x_0)*{\Delta}x \]

将一阶泰勒展开代入Loss函数得

\[Loss_{(t)} = \sum\nolimits_{i=1}^{n}{l(y_i,{\hat{y}}_i^{(t-1)}+f_t(x_i))}=\sum\nolimits_{i=1}^{n}{l(y_i, {\hat{y}}_i^{t-1})+\frac{\partial{l(y_i, {\hat{y}}_i^{t-1})}}{\partial{{\hat{y}}_i^{t-1}}}*{f_t{(x_i)}}}\\ Loss_{(t)} =Loss_{(t-1)}+\sum\nolimits_{i=1}^{n}{l'(y_i, {\hat{y}}_i^{t-1})*f_t{(x_i)}} \]

要使得Loss在本轮下降,即保证\(l'(y_i, {\hat{y}}_i^{t-1})*f_t{(x_i)} < 0\),只要保证\(f_t{(x_i)}=-l'(y_i, {\hat{y}}_i^{t-1})\)即可,即本轮树拟合上一轮的负梯度。当损失函数为MSE时,负梯度就是上一轮的残差。

这里有个问题为什么拟合负梯度,而不是保证和梯度相反的随机值。我个人理解是因为当梯度更大时,上一轮的拟合值离Loss最小值更远,所以本轮走的步长应该更长,所以拟合值的大小与梯度大小是相关的。这个理解有个限制:保证Loss是凸函数,但似乎常用的Loss函数都是凸函数,不知道是不是故意这样设计的。比如回归问题中的\(MSE、MAE、log(cosh(y-{\hat{y}}))\),分类问题中的\(-ylog(y)-(1-y)log(1-y)\)

XGBoost推导

Loss函数/目标函数

相比GBDT,xgboost做了几点提升

  1. 使用二阶泰勒展开,余项更小,能更精准地逼近真实的损失函数
  2. 添加正则项,限制树结构,防止过拟合
  3. ....

XGBoost的损失函数(目标函数)

\[Object=\sum_{i=1}^{n}{l({y}_i, {\hat{y}}_i)}+\sum_{k=1}^{K}{\Omega{(f_k)}}\\ {\Omega}(f)={\gamma}T+\frac{1}{2}{\lambda}||w||^2 \]

代入二阶泰勒展开

泰勒二阶展开极其变形

\[f(x){\approx}f(x_0)+f'(x_0)(x-x_0)+\frac{f''(x_0)}{2}(x-x_0)^2\\ f(x_0+{\Delta}x){\approx}f(x_0)+f'(x_0)*{\Delta}x+\frac{f''(x_0)}{2}*{\Delta}x^2 \]

把二阶泰勒展开代入Loss得

\[Obj=\sum_{i=1}^{n}{\large{[}}l(y_i, {\hat{y}}^{(t-1)})+g_if_t(x_i)+\frac{1}{2}h_if_i^2{(x_i)}{\large{]}}+{\Omega}{(f_t)}\\ g_i=\partial_{{\hat{y}}^{(t-1)}}(l(y_i, {\hat{y}}^{(t-1)})), \quad h_i=\partial^2_{{\hat{y}}^{(t-1)}}(l(y_i, {\hat{y}}^{(t-1)})) \]

Loss变形,把遍历n个样本变为遍历每个叶子节点,\(I_j\)表示第\(j\)个叶子结点内的样本ID的集合。

\[\begin{align} Obj &= \sum_{i=1}^n{[g_if_t{(x_i)}+\frac{1}{2}h_if_t^2{(x_i)}]}+{\gamma}T+\frac{1}{2}{\lambda}\sum_{i=1}^T{w_j^2}\\ &= \sum_{j=1}^T{[(\sum_{i\in{I_j}}g_i)w_j+\frac{1}{2}(\sum_{i\in{I_j}}h_i+{\lambda})w_j^2]+{\gamma}T} \end{align} \]

这个变形很巧妙的一点就是把正则融入到了损失函数里,方便对\(w_j\)求解

把Loss看做以\(w_j\)为变量的二次函数,求解\(w_j\)

\[w_j=-\frac{\sum_{i\in{I_j}}g_i}{\sum_{i\in{I_j}}h_i+{\lambda}} \]

代入Loss求最优解

\[Obj=-\frac{1}{2}\sum_{j=1}^{T}{\frac{(\sum\nolimits_{i{\in}I_j}g_i)^2}{\sum\nolimits_{i{\in}I_j}h_i+{\lambda}}}+{\gamma}T\\ Obj=-\frac{1}{2}\sum_{j=1}^{T}{\frac{(G_j)^2}{H_j+{\lambda}}}+{\gamma}T\\ G_j=\sum\nolimits_{i{\in}I_j}g_i,H_j=\sum\nolimits_{i{\in}I_j}h_i \]

这里有个问题是,\(w_j\)是Loss极小值的解,还是极大值的解。个人理解,如果Loss函数为凸函数,则二阶导\(h_i>0\)\(\sum_{i\in{I_j}}h_i+{\lambda}>0\),那Loss最优解对应的二次函数二次项为正,开口朝上,为极小值的解。

如果Loss函数非凸,就母鸡了。与上述问题相同,Loss函数似乎都是凸函数?

求取分裂增益

求取增益时只需要考虑两个点

  1. 增益=分裂前得Loss-分裂后的Loss
  2. 增益只与叶子节点相关

那么增益如下

\[\begin{align} Gain_{split} &={\LARGE{(}}-\frac{G^2}{2(H+{\lambda})}+{\gamma}{\LARGE{)}}-{\LARGE{(}}-\frac{G_L^2}{2(H_L+{\lambda})}+{\gamma}-\frac{G_R^2}{2(H_R+{\lambda})}+{\gamma}{\LARGE{)}}\\ &=\frac{1}{2}{\LARGE{(}}\frac{G_L^2}{H_L+{\lambda}}+\frac{G_R^2}{H_R+{\lambda}}-\frac{G^2}{H+{\lambda}}{\LARGE{)}}-{\gamma} \end{align} \]

XGBoost的优化

针对GBDT做的优化

  1. 二阶泰勒展开
  2. 正则
  3. 缺失值处理:xgboost可以指定哪种取值是缺失值。所以可以把Nan输入到模型内?待验证。https://tech.meituan.com/2019/08/15/problems-caused-by-missing-xgboost-values-and-their-in-depth-analysis.html
  4. 并行计算
  5. 缩放
  6. 列抽样
  7. 支持自定义Loss函数
  8. 特征分桶,过于复杂, 看不懂(https://yxzf.github.io/2017/04/xgboost-v2/)

原paper地址

github地址+讨论

文档

posted @ 2020-10-17 23:09  wa007  阅读(130)  评论(0编辑  收藏  举报