背景
在GBDT的基础上,有了XGB。XGB"(eXtreme Gradient Boosting极端梯度提升)本质还是 一个GBDT (Gradien tBoosting Decision Tree),XGB (Xtreme Gradient Boosting) 的本质还是一个GBDT, 但是在速度和效率上都发挥到了极致,XGB和GBDT比较大的不同就是目标函数的定义。
原理
XGB使用泰勒展开来近似目标函数。
二阶泰勒展开公式:

最小化下列损失函数,

γ\gammaγ和λ\lambdaλ是预先设定的超参数, TTT是叶子节点的数量,www是叶子结点的权重。

化简后:

gi=∂y^(t−1)l(yi,y^(t−1))g_{i}=\partial_{\hat{y}^{(t-1)}} l\left(y_{i}, \hat{y}^{(t-1)}\right)gi=∂y^(t−1)l(yi,y^(t−1)), 表示损失对y^(t−1)\hat{y}^{(t-1)}y^(t−1)求导。
hi=∂y^(t−1)2l(yi,y^(t−1))h_{i}=\partial_{\hat{y}(t-1)}^{2} l\left(y_{i}, \hat{y}^{(t-1)}\right)hi=∂y^(t−1)2l(yi,y^(t−1)), 表示损失对y^(t−1)\hat{y}^{(t-1)}y^(t−1)求导。
可以得到:
gi=∂y^(t−1)l(yi,y^(t−1))=∂y^(t−1)(yi−y^(t−1))2=−2yi+2y^(t−1)\begin{matrix}{}
{{g_i} = {\partial _{{{\hat y}^{(t - 1)}}}}l\left( {{y_i},{{\hat y}^{(t - 1)}}} \right)}\\
{\kern 10pt} = {\partial _{{{\hat y}^{(t - 1)}}}}{({y_i} - {{\hat y}^{(t - 1)}})^2}\\
{\kern -8pt} = {\rm{ - 2}}{y_i} + 2{{\hat y}^{(t - 1)}}
\end{matrix}gi=∂y^(t−1)l(yi,y^(t−1))=∂y^(t−1)(yi−y^(t−1))2=−2yi+2y^(t−1)
hi=∂y^(t−1)2l(yi,y^(t−1))=2{h_i} = \partial _{\hat y(t - 1)}^2l\left( {{y_i},{{\hat y}^{(t - 1)}}} \right) = 2hi=∂y^(t−1)2l(yi,y^(t−1))=2
gig_igi和hih_ihi的结果带入公式展开,可以得到和原公式展开相同的结果。
为啥公式的第一行的ft(xi)f_t(\bf{x_i})ft(xi)消失了,因为这个得到的结果也是对应叶子节点的权重。注解:最后一步的转化思路是从在这个树中,每个样本落在哪个节点上转为了每个节点 上有哪些样本。

这个是对wjw_jwj做了求导,将最外层的求和符号去掉,然后就可以得到最后的结果。

这个是将优化后的www带进去,然后得到的结果。
3. XGBoost在什么地方做的剪枝,怎么做的?
(1) 当引入的分割带来的增益小于一个阈值时,我们就可以减掉这个分割(参考决策树的分割)。

(2)在模型中加入正则
- XGBoost特征重要性实现原理:
每个特征对应一个模型参数wiw_iwi,这个参数越大说明这个特征越重要。
gain :该特征在其出现过的所有树中产生的平均增益(我自己的理解就是目标函数减少值总和的平均值,这里也可以使用增益之和)。
每一个特征的分裂都会产生好多树,那么这些树是会带来增益的。
代码训练
#训练集和验证集数据划分
import xgboost as xgb
#train_x是DataFrame数据,选择对应的列就行
nums = int(train_x.shape[0] * 0.80)
# 训练集验证集划分
trn_x, trn_y, val_x, val_y = train_x[:nums], train_y[:nums], train_x[nums:], train_y[nums:]
#训练集
train_matrix = xgb.DMatrix(trn_x, label=trn_y.values, missing=np.nan)
valid_matrix = xgb.DMatrix(val_x, label=val_y.values, missing=np.nan)
# test_matrix = clf.DMatrix(test_x, label=val_y, missing=np.nan)
test_matrix = xgb.DMatrix(test_x, missing=np.nan)
params = {'booster': 'gbtree',
'eval_metric': 'mae',
'min_child_weight': 5,
'max_depth': 8,
'subsample': 0.5,
'colsample_bytree': 0.5,
'eta': 0.0015,
'seed': 2020,
'nthread': 4,
'silent': True,
}
watchlist = [(train_matrix, 'train'), (valid_matrix, 'eval')]
model = xgb.train(params, train_matrix, num_boost_round=50000, evals=watchlist, verbose_eval=500,
early_stopping_rounds=1000)
#划分的验证集数据
val_pred = model.predict(valid_matrix, ntree_limit=model.best_ntree_limit).reshape(-1, 1)
#需要测试的数据
test_pred = model.predict(test_matrix, ntree_limit=model.best_ntree_limit).reshape(-1, 1)
问题
XGBoost为什么要用二阶泰勒展开
- 二阶信息本身就能让梯度收敛更快更准确。这一点在优化算法里的牛顿法里已经证实了。可以简单认为一阶导指引梯度方向,二阶导指引梯度方向如何变化。
- 不同损失的求导是不一样的,为了可以统一损失函数求导的形式,所以用二阶泰勒展开。
参考资料
https://zhuanlan.zhihu.com/p/290964953?utm_source=ZHShareTargetIDMore (这个博客里面树模型比较详细)
1903

被折叠的 条评论
为什么被折叠?



