第 9 章 · 03 GBM 基线 本节摘要:本节进入集成的另一大流派——提升(boosting)。上一节的 Bagging/随机森林是「并行训深树再平均」降方差,提升则是「串行训浅树补错误」降偏差。本节从最早的 AdaBoost 讲到现代的梯度提升机(GBM),并落地一个 sklearn GBM 基线。本节讲清四件事:AdaBoost 如何通过「提高错分样本权重」让后续弱学习器聚焦难例;梯度提升如何把「拟合残差」推广为「拟合损失函数的负梯度」,从而支持任意可微损失;sklearn 的 有哪些关键超参(学习率、树数、深度、子采样);以及如何用 配合 做超参搜索。读完本节,你理解了「为什么 GBM 是过去十年结构化数据上最成功的算法」的原理,并训练了一个可用的基线模型。
本节摘要:本节进入集成的另一大流派——提升(boosting)。上一节的 Bagging/随机森林是「并行训深树再平均」降方差,提升则是「串行训浅树补错误」降偏差。本节从最早的 AdaBoost 讲到现代的梯度提升机(GBM),并落地一个 sklearn GBM 基线。本节讲清四件事:AdaBoost 如何通过「提高错分样本权重」让后续弱学习器聚焦难例;梯度提升如何把「拟合残差」推广为「拟合损失函数的负梯度」,从而支持任意可微损失;sklearn 的
GradientBoostingClassifier有哪些关键超参(学习率、树数、深度、子采样);以及如何用OneStepTimeSeriesSplit配合GridSearchCV做超参搜索。读完本节,你理解了「为什么 GBM 是过去十年结构化数据上最成功的算法」的原理,并训练了一个可用的基线模型。
内容来源:原项目
12_gradient_boosting_machines/01_boosting_baseline.ipynb、02_sklearn_gbm_tuning.ipynb,汉化并套用体系化模板。
⚠️ 学习提示:GBM 比随机森林更容易过拟合——它执念于「把训练误差压下去」,稍不留神就在噪声上拟合出虚假模式。学习率与树数必须配合早停使用。
阅读完本节,你应当能够:
OneStepTimeSeriesSplit 给 GBM 做时序超参搜索。提升的起点是 AdaBoost(Freund & Schapire, 1997)。它用浅树(甚至是只有一个分裂的「树桩 stump」)作弱学习器,串行训练,每轮调整样本权重:把上一轮错分的样本权重调高,正确的调低,让下一棵树更关注难例。最终模型是所有弱学习器的加权组合,权重反映各自的训练误差贡献。
梯度提升(Friedman, 1999)把这套思想做了关键推广:新树不去拟合加权样本,而是去拟合当前模型损失函数的负梯度。对于平方损失,负梯度恰好就是残差 y - \hat{y};但换成其他损失(绝对损失、Huber、logloss 等),负梯度会自动跟着变——这让 GBM 支持任意可微损失,远比只能做指数损失的 AdaBoost 灵活。
💡 核心心法:Bagging 是「让许多独立的强模型投票」降方差;Boosting 是「让许多相关的弱模型接力补错」降偏差。前者用深树(低偏差高方差),后者用浅树(高偏差低方差)。两套思路在偏差-方差权衡的两端各自发力。
notebook 01_boosting_baseline.ipynb 把 sklearn 的 AdaBoostClassifier、GradientBoostingClassifier 与三大主流库(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_change、validation_fraction实现这一机制。
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 段全程不碰,最后做一次「诚实」的样本外评估——这是避免「调参调出过拟合」的关键纪律。
notebook 还提到了较新的 HistGradientBoostingClassifier——它借鉴 LightGBM 的直方图加速思路,在 sklearn 里把训练速度提到与 LightGBM 一个量级,数据量大时优先考虑它,而非老的 GradientBoostingClassifier。
n_estimators(树数)与 max_depth(单树复杂度),配合 learning_rate 与 subsample 正则化。subsample<1 引入 Bagging 风格的方差下降。下一节,我们看 LightGBM 与 CatBoost 交易信号——两大工业级 GBM 实现的工程加速原理与类别特征处理,以及如何生成可回测的交易信号。