XGBoost (一)优化思路

XGBoost(Extreme Gradient Boosting)2014 年由陈天奇开发,旨在对传统梯度提升算法(GBDT)进行高效实现和优化。2015 年,XGBoost 在 Kaggle 竞赛中表现卓越,多个冠军队伍使用了 XGBoost,横扫众多榜单。凭借卓越的性能和广泛的适用性,XGBoost 很快成为竞赛和工业界的标配算法,被广泛应用于金融风控、推荐系统、广告点击率预测、科研建模等领域。

文档:https://xgboost.readthedocs.io/en/stable
论文:https://arxiv.org/pdf/1603.02754

在传统 GBDT 中,模型每一棵树的目标就是降低训练误差,但这种训练方式存在两类结构性问题:树结构不受约束,以及叶子输出容易数值不稳定。XGBoost 的核心创新,正是系统性地重写这两类复杂度,让模型既能更稳,也能更准。

1. 结构复杂度

传统 GBDT 训练时,每棵树都会不断分裂节点来降低训练误差。分裂越多,叶子覆盖的样本越少,极端情况下,一个叶子只覆盖一个样本,训练误差几乎为零,完全贴合训练数据,导致过拟合。

常见做法是给树设上硬性限制,比如最大深度或叶子数量,用来阻挡过度生长。问题在于这些限制太粗暴:

  • 有些分裂虽然会让树变深,但带来的误差下降非常可观,却因为触碰到超参数上限而被硬拦下来。
  • 有些分裂虽然能带来一点点误差下降,但相比它增加的模型复杂度,其价值并不高,却因为没有触发限制而被轻易放行。

理想的方式是:每次分裂都既看误差是否下降,也看结构复杂度是否值得增加。这样,高价值分裂自然被保留,价值低的分裂自然熄火。硬性超参数退到“保底位”,只在模型真的往失控方向冲时介入,而不干扰正常的分裂选择。

XGBoost 正是沿着这个思路引入了结构复杂度正则项。它把新增叶子的复杂度直接放进目标函数里。一次分裂能不能通过,不只看损失下降多少,而要看收益能否抵消复杂度成本。如果划不来,这次分裂就被拒绝。

有了这套机制,树的生长从“被外力限制”变成“在优化中自我调节”。模型既能保留真正有意义的结构,又能避免无效膨胀,从而得到更合理、灵活且泛化更强的树。

2. 输出复杂度

传统 GBDT 在确定叶子节点的输出时,会直接根据节点中样本的一阶导数和二阶导数计算更新量:

然而在许多任务中,尤其是分类问题,叶子节点上的二阶导可能非常小,甚至接近于零。当二阶导过小,叶子节点的更新值会被异常放大,从而导致模型对该叶子所覆盖样本做出不合理的大幅度预测调整。假设某个叶子里 \(G_{j} = -10\),而 \(H_{j}=0.01\),则 \(\gamma_{j} = 1000\)。

这样不仅可能破坏损失下降的趋势,还会让训练进入震荡和不稳定的状态,使得后续树被迫不断修补前一棵树的误差,整体优化过程随之恶化。

XGBoost 在目标函数中引入了叶子输出的 L2 正则化,通过对叶子输出值施加惩罚,使得叶子节点的输出值被进一步平滑化,使得模型的更新不会因局部不稳定的梯度而出现极端值,同时也提升了整体优化的可控性。