6.3 Gradient Boosting 与 XGBoost:每棵新树拟合当前损失的下降方向
随机森林让许多树分别判断再平均。模型工坊接到的新任务不同:少数高代价样本仍被系统性低估,团队希望每轮都针对当前目标函数还没有解决的部分继续修正。
Gradient Boosting 构造一个加法模型。新树不是泛泛“关注错题”,而是在当前预测处拟合损失对函数值的负梯度;平方损失下,这个方向恰好与 residual 对应。
本课目标
- 用函数梯度解释 gradient boosting;
- 理解 squared loss residual 只是一个特例;
- 看懂 XGBoost 的二阶近似、叶权重和正则项;
- 正确划分 train、validation 与 test 并使用 early stopping;
- 联合分析学习率、树容量、采样、校准和工程成本。
1. 加法模型
从常数模型 $F_0(x)$ 开始,第 $t$ 轮加入一棵树:
$$ F_t(x)=F_{t-1}(x)+\eta f_t(x), $$
其中 $\eta$ 是 learning rate/shrinkage。训练目标是经验损失和复杂度约束,而不是“让每棵树单独准确”。
在函数空间的 gradient boosting 中,对每个样本计算 pseudo-residual:
$$ r_{it}=-\left.\frac{\partial\ell(y_i,F(x_i))}{\partial F(x_i)}\right|{F=F{t-1}}. $$
新树拟合 $r_{it}$ 或相应 Newton step,再通过步长加入当前模型。
2. Residual 是平方损失的特例
若:
$$ \ell(y,F)=\frac12(y-F)^2, $$
则:
$$ -\frac{\partial\ell}{\partial F}=y-F, $$
正好是 ordinary residual。
但 binary log loss 通常在 logit/raw-score 空间优化。令 $p=\sigma(F)$,单样本负对数似然的梯度为:
$$ g=\frac{\partial\ell}{\partial F}=p-y, $$
负梯度是 $y-p$,不是“分错为 1、分对为 0”的标签。对 ranking、Poisson、quantile 等目标,pseudo-residual 又不同。因此“新树拟合上一棵树的错误”只是一句粗略直觉。
3. XGBoost 的二阶局部目标
XGBoost 在第 $t$ 轮考虑:
$$ \mathcal L^{(t)}=\sum_i\ell(y_i,\hat y_i^{(t-1)}+f_t(x_i))+\Omega(f_t). $$
对当前预测做二阶 Taylor expansion,去掉与新树无关的常数:
$$ \widetilde{\mathcal L}^{(t)} =\sum_i\left[g_if_t(x_i)+\frac12h_if_t(x_i)^2\right]+\Omega(f_t), $$
其中:
$$ g_i=\partial_{\hat y}\ell(y_i,\hat y_i),\qquad h_i=\partial^2_{\hat y}\ell(y_i,\hat y_i). $$
若一棵树有 $T$ 个叶子、叶权重为 $w_j$,常见正则形式是:
$$ \Omega(f)=\gamma T+\frac12\lambda\sum_{j=1}^Tw_j^2 $$
(实现还可支持 L1 等项)。对落入叶 $j$ 的样本集合 $I_j$,记 $G_j=\sum_{i\in I_j}g_i$、$H_j=\sum_{i\in I_j}h_i$,在 L2 情形下该叶的最优局部权重为:
$$ w_j^*=-\frac{G_j}{H_j+\lambda}. $$
候选分裂的 gain 来自“分裂后两个叶子的最佳目标值”与“未分裂叶子”之差,再扣除新叶复杂度。二阶信息不是抽象的“更准”,而是用于估计当前局部曲率和 Newton-style 更新。
4. 容量参数不是独立旋钮
Learning rate 与轮数
较小 $\eta$ 通常需要更多 boosting rounds。它可能使路径更平滑,但不会自动防止过拟合;轮数仍要由 validation 选择。
树结构
max_depth、max_leaves/grow policy 控制交互复杂度;min_child_weight 约束叶中 Hessian 权重,不等同于固定样本数;gamma/minimum split loss 要求足够分裂收益。
叶权重正则
L2 reg_lambda、L1 reg_alpha 收缩叶值。不同目标下 Hessian 尺度不同,相同参数值不能脱离 objective 比较。
行列采样
subsample、colsample_bytree 等引入随机性,可降低相关性/成本,但太低会丢信号并增大随机波动。
这些参数相互作用。不存在通用的“先深度、再正则、最后采样”唯一调参顺序;应先固定验证协议和搜索预算,再围绕容量、步长与成本联合比较。
5. Histogram、稀疏与类别支持
精确扫描所有连续阈值成本高。Histogram 方法先把值映射到 bins,再在累计 gradient/Hessian 统计上评估切分。Bin 数影响速度、内存和近似精度。
XGBoost 等实现可为缺失值学习默认分支方向,但这不等于缺失机制已被正确建模。训练与部署的 NaN 含义应一致,并监控缺失率漂移。
原生 categorical、类别分组与 one-hot 策略随库和版本变化。不要把任意整数编码直接当连续数值;应查当前版本文档、固定依赖,并用未见类别做部署测试。
6. Early stopping 必须使用 validation
数据职责应分开:
- train:拟合每轮树与叶权重;
- validation:选择轮数、参数与阈值;
- test:在所有选择冻结后评估一次。
把 test 放进 eval_set 做 early stopping,会让 test 参与模型选择。最终数字不再是未接触数据上的估计。
当前 XGBoost sklearn interface 的训练骨架如下;实际项目应固定并核对依赖版本:
from xgboost import XGBClassifier
from sklearn.metrics import log_loss
model = XGBClassifier(
objective="binary:logistic",
eval_metric="logloss",
tree_method="hist",
n_estimators=2_000,
learning_rate=0.05,
max_depth=4,
min_child_weight=5,
subsample=0.8,
colsample_bytree=0.8,
reg_lambda=1.0,
early_stopping_rounds=50,
random_state=42,
)
model.fit(
X_train,
y_train,
eval_set=[(X_valid, y_valid)],
verbose=False,
)
# sklearn interface 会在预测时使用 early stopping 选出的最佳轮次。
test_probability = model.predict_proba(X_test)[:, 1]
print("test log loss:", log_loss(y_test, test_probability))不要根据 test loss 继续改 max_depth 或 learning rate;一旦这样做,原 test 已变成 validation,需要新的独立测试数据或 nested evaluation。
7. Native API 的最佳轮次陷阱
使用 xgboost.train 时,early stopping 默认返回的是最后一轮模型,而不是把 booster 截断为最佳轮次。预测需要显式指定类似:
best_probability = booster.predict(
dtest,
iteration_range=(0, booster.best_iteration + 1),
)或使用支持 save_best=True 的 early-stopping callback。还要注意:多个 evals/metrics 时,具体哪个数据集与指标控制停止由 API 规则决定,必须核对日志和当前官方文档。
这类行为会随接口版本调整,所以代码审查不能只看“设置了 early_stopping_rounds”,还要验证最终预测实际用了哪几轮。
8. Bagging 与 Boosting 的差异
| 维度 | Random Forest / Bagging | Gradient Boosting |
|---|---|---|
| 训练依赖 | 树大体可独立、并行 | 第 $t$ 轮依赖前 $t-1$ 轮 |
| 组合 | 概率/预测平均 | 加法累积 raw score/预测 |
| 多样性来源 | bootstrap、特征随机等 | 当前梯度、采样与树约束 |
| 轮数作用 | 平均逐渐稳定,收益平台 | 持续改变模型容量,需选最佳轮次 |
| 常见风险 | 深树体积、相关误差、概率失准 | 对噪声/漂移敏感、调参耦合、串行训练 |
“Bagging 降方差、Boosting 降偏差”可作入门启发,但不是定律。Bagging 也会改变 bias,Boosting 也可能降低或放大 variance;结果取决于基学习器、损失、正则和数据生成过程。
9. 评估不能停在一个 AUC
Boosted trees 常有很强排序能力,但 sigmoid/softprob 输出不保证校准。Class weights、undersampling、目标错设和分布变化都会改变概率语义。
至少检查:
- validation/test 的 log loss、Brier、AUC/PR 与业务成本;
- reliability curve 和不同时间/群体的 calibration;
- 最佳轮次在 fold 间是否稳定;
- 特征缺失率、raw score 与预测分布漂移;
- 推理延迟、模型体积和峰值内存。
若做 post-hoc calibration,校准数据必须独立于 base learner 的拟合,或使用交叉拟合。
10. 解释与外推边界
Gain、weight、cover 等 importance 定义不同,都会受相关特征和训练路径影响。SHAP 等解释工具描述的是给定模型相对某个背景分布的贡献分解,不自动提供因果解释,背景数据选择也会改变结论。
树集成在训练范围外通常延续已有叶值,不能像正确设定的线性/机制模型那样自然外推趋势。面对长期趋势、价格曲线或物理约束,应显式做 out-of-range 测试,必要时加入单调约束、机制特征或选择其他模型。
常见误区
- Boosting 就是反复拟合错分样本:一般目标下拟合的是负梯度/Newton 方向。
- 二阶近似天然更准确:它利用局部曲率,结果仍取决于目标与近似条件。
- 深度 3–6 是固定答案:树生长策略、数据和交互阶数不同。
- 用了 early stopping 就没有泄漏:控制停止的数据集必须是 validation,不是 test。
- 更多轮数只会更好:轮数是模型容量的一部分。
练习
- 推导 squared loss 与 binary log loss 的 gradient/Hessian。
- 在固定 split 下画 train/validation loss,并标出 best iteration。
- 比较 sklearn interface 与 native API 是否使用同一最佳轮次预测。
- 联合改变 learning rate 与 rounds,比较性能、训练时间和模型大小。
- 构造超出训练范围的输入,比较线性模型、随机森林和 boosting 的外推。
小结
Gradient Boosting 顺序构造加法模型,新树沿当前损失的下降方向修正预测。XGBoost 用 gradient、Hessian、结构惩罚与采样把这个过程变成可扩展的树优化系统。真正可靠的训练流程还需要独立 validation、正确的最佳轮次预测、概率评估与部署监控。
下一章离开有标签监督:先问无监督方法究竟优化什么,再讨论聚类、降维和异常检测的验证边界。