第 9 章 · 03 GBM 基线


文档摘要

第 9 章 · 03 GBM 基线 本节摘要:本节进入集成的另一大流派——提升(boosting)。上一节的 Bagging/随机森林是「并行训深树再平均」降方差,提升则是「串行训浅树补错误」降偏差。本节从最早的 AdaBoost 讲到现代的梯度提升机(GBM),并落地一个 sklearn GBM 基线。本节讲清四件事:AdaBoost 如何通过「提高错分样本权重」让后续弱学习器聚焦难例;梯度提升如何把「拟合残差」推广为「拟合损失函数的负梯度」,从而支持任意可微损失;sklearn 的 有哪些关键超参(学习率、树数、深度、子采样);以及如何用 配合 做超参搜索。读完本节,你理解了「为什么 GBM 是过去十年结构化数据上最成功的算法」的原理,并训练了一个可用的基线模型。

第 9 章 · 03 GBM 基线

本节摘要:本节进入集成的另一大流派——提升(boosting)。上一节的 Bagging/随机森林是「并行训深树再平均」降方差,提升则是「串行训浅树补错误」降偏差。本节从最早的 AdaBoost 讲到现代的梯度提升机(GBM),并落地一个 sklearn GBM 基线。本节讲清四件事:AdaBoost 如何通过「提高错分样本权重」让后续弱学习器聚焦难例;梯度提升如何把「拟合残差」推广为「拟合损失函数的负梯度」,从而支持任意可微损失;sklearn 的 GradientBoostingClassifier 有哪些关键超参(学习率、树数、深度、子采样);以及如何用 OneStepTimeSeriesSplit 配合 GridSearchCV 做超参搜索。读完本节,你理解了「为什么 GBM 是过去十年结构化数据上最成功的算法」的原理,并训练了一个可用的基线模型。

内容来源:原项目 12_gradient_boosting_machines/01_boosting_baseline.ipynb02_sklearn_gbm_tuning.ipynb,汉化并套用体系化模板。

⚠️ 学习提示:GBM 比随机森林更容易过拟合——它执念于「把训练误差压下去」,稍不留神就在噪声上拟合出虚假模式。学习率与树数必须配合早停使用。

学习目标

阅读完本节,你应当能够:

  1. 对比 AdaBoostBagging 在样本权重处理上的差别。
  2. 解释梯度提升为何是「拟合负梯度」而非只是「拟合残差」。
  3. 列举 sklearn GBM 的关键超参及其正则化作用。
  4. 区分 shrinkage(学习率)subsample 两种正则化思路。
  5. OneStepTimeSeriesSplit 给 GBM 做时序超参搜索。

一、从 AdaBoost 到梯度提升

提升的起点是 AdaBoost(Freund & Schapire, 1997)。它用浅树(甚至是只有一个分裂的「树桩 stump」)作弱学习器,串行训练,每轮调整样本权重:把上一轮错分的样本权重调高,正确的调低,让下一棵树更关注难例。最终模型是所有弱学习器的加权组合,权重反映各自的训练误差贡献。

梯度提升(Friedman, 1999)把这套思想做了关键推广:新树不去拟合加权样本,而是去拟合当前模型损失函数的负梯度。对于平方损失,负梯度恰好就是残差 y - \hat{y};但换成其他损失(绝对损失、Huber、logloss 等),负梯度会自动跟着变——这让 GBM 支持任意可微损失,远比只能做指数损失的 AdaBoost 灵活。

💡 核心心法:Bagging 是「让许多独立的强模型投票」降方差;Boosting 是「让许多相关的弱模型接力补错」降偏差。前者用深树(低偏差高方差),后者用浅树(高偏差低方差)。两套思路在偏差-方差权衡的两端各自发力。

二、AdaBoost 与多库对比基线

notebook 01_boosting_baseline.ipynb 把 sklearn 的 AdaBoostClassifierGradientBoostingClassifier 与三大主流库(XGBoost、LightGBM、CatBoost)以及一个 DummyClassifier(总是预测多数类)做横向对比:

from sklearn.ensemble import AdaBoostClassifier, GradientBoostingClassifier, RandomForestClassifier from xgboost import XGBClassifier from lightgbm import LGBMClassifier from catboost import CatBoostClassifier from sklearn.dummy import DummyClassifier # 各模型默认配置做交叉验证对比

数据是第 4 章构造的 engineered_features,按 holding_period=1 取 1 个月前瞻收益的方向(涨/跌)作分类标签:

def get_data(start='2000', end='2018', task='classification', holding_period=1, dropna=False): target = f'target_{holding_period}m' with pd.HDFStore(DATA_STORE) as store: df = store['engineered_features'] y = (df[target] > 0).astype(int) X = df.drop([c for c in df.columns if c.startswith('target')], axis=1) return y, X

DummyClassifier 是基线之基线——如果你的模型连它都打不过,说明信号完全是噪声。

三、梯度提升的关键超参

GBM 的性能由两大杠杆驱动:集成的规模(树数)每棵树的复杂度。sklearn 的 GradientBoostingClassifier 关键参数:

gb_clf = GradientBoostingClassifier(loss='deviance', learning_rate=0.1, n_estimators=100, subsample=1.0, max_depth=3, min_samples_leaf=1, random_state=42)
超参 含义 调参方向
n_estimators 树的数量(迭代轮数) 越多越能降偏差,但过拟合风险上升
learning_rate shrinkage,每棵树贡献的缩放系数 越小越稳,但需更多树补偿
max_depth 每棵树的深度,典型 3 越深越能学交互,但易过拟合
subsample 每棵树用的行比例,<1.0 即随机梯度提升 引入随机性,降方差
min_samples_leaf 叶节点最小样本数 调大抗过拟合
loss 损失函数,deviance 即 logloss 也可换 exponential 退化为 AdaBoost

两种正则化思路

思路 实现 效果
shrinkage learning_rate 调小 每棵树「步子小」,需更多树,但泛化更稳
随机化 subsample < 1.0 + 列抽样 引入 Bagging 风格的随机性,降方差

实务经验:学习率 × 树数 是一对联动参数,典型组合是「小学习率(0.010.05)+ 多树(5003000)+ 早停」。两者乘积近似决定最终拟合强度,但小学习率配多树的泛化通常优于大学习率配少树。

⚠️ 没有早停就是定时炸弹:GBM 跑太多轮必然过拟合。务必在验证集上监控 IC 或对数损失,一旦连续若干轮不改善就停——sklearn 用 n_iter_no_changevalidation_fraction 实现这一机制。

四、用 OneStepTimeSeriesSplit 调参

notebook 02_sklearn_gbm_tuning.ipynb 实现了一个时序专用的 CV 切分:

class OneStepTimeSeriesSplit: """生成训练/测试索引对,假设索引含 'date' 层级""" def __init__(self, n_splits=3, test_period_length=1, shuffle=False): self.n_splits = n_splits self.test_period_length = test_period_length self.test_end = n_splits * test_period_length

它的逻辑是「训练段在测试段之前,每个测试段长度固定(如 1 个月),依次向前滚动」。这严格符合金融数据的时间结构——绝不让未来进入训练集。

调参时还构造了一个留出测试集(holdout):

def get_holdout_set(target, features, period=6): dates = np.sort(target.index.get_level_values('date').unique()) cv_start, cv_end = dates[0], dates[-period - 2] holdout_start, holdout_end = dates[-period - 1], dates[-1] # 训练用 cv_start~cv_end,holdout 用最后 period 个月

调参只在 CV 段做,holdout 段全程不碰,最后做一次「诚实」的样本外评估——这是避免「调参调出过拟合」的关键纪律。

sklearn 也有 HistGradientBoosting

notebook 还提到了较新的 HistGradientBoostingClassifier——它借鉴 LightGBM 的直方图加速思路,在 sklearn 里把训练速度提到与 LightGBM 一个量级,数据量大时优先考虑它,而非老的 GradientBoostingClassifier

本节要点回顾

  1. 两套集成:Bagging 并行训深树降方差;Boosting 串行训浅树补错降偏差。
  2. AdaBoost:调样本权重让后续弱树聚焦难例,但只能配合指数损失。
  3. 梯度提升:新树拟合当前模型损失函数的负梯度(平方损失下即残差),支持任意可微损失——这是它取代 AdaBoost 的关键。
  4. 两大杠杆:n_estimators(树数)与 max_depth(单树复杂度),配合 learning_ratesubsample 正则化。
  5. shrinkage + 随机化:小学习率配多树通常泛化更稳;subsample<1 引入 Bagging 风格的方差下降。
  6. 早停 + 时序 CV + holdout:GBM 必须用早停防过拟合,调参只用时序 CV,留一段 holdout 做诚实评估。

下一节,我们看 LightGBM 与 CatBoost 交易信号——两大工业级 GBM 实现的工程加速原理与类别特征处理,以及如何生成可回测的交易信号。


发布者: 作者: 灏天文库 转发
评论区 (0)
U