🏠 总目录📚 本教程 04a · 集成学习与 GBDT ← →
📑 本页目录(点开跳转)

04A / 先看直觉,再看细节

一棵树不够,
可以一起投票,也可以接着纠错。

随机森林让多棵树并行投票;GBDT 按顺序添加新树,改进当前预测。

先抓住一个具体结果

新树只补一点

某个样本原预测为 3,新树建议加 1,学习率为 0.1,那么更新后是 3.1。新树的输出不是最终答案;一般损失下它学习的是负梯度方向。

GBDT 的加法更新

$$F_t(x)=F_{t-1}(x)+\eta f_t(x)$$

接下来,按需要选一项

你现在想看什么?

这些入口是选择,不是必须按顺序完成的任务。

可以停在这里

随机森林让多棵树并行投票;GBDT 按顺序添加新树,改进当前预测。

需要更多细节时,继续看完整正文 →
继续探索

原有正文、图解和例子都在下方。按需跳转,不必一次读完。

04a · 集成学习与 GBDT

Bagging并行 · 各train各的树1树2树3树4数据→ 投票/平均降【方差】Boosting串行 · 补前一个的错树1树2补错树3再补树4再补→ 加权求和降【偏差】都是「很多棵树」,但组织方式和治的病完全不同⭐ Bagging 的树可以并行训、深一点无所谓;Boosting 必须串行、每棵要浅(否则第一棵就过拟合了)所以随机森林调「树多少棵」,GBDT 调「学习率 + 树深」
都是「很多棵树」,但组织方式和治的病完全不同:Bagging 并行降方差,Boosting 串行降偏差。⭐ 所以随机森林主要调「多少棵」,GBDT 主要调「学习率 + 树深」。

⏱ 34 分钟 | ⭐ 集成的收益全部来自成员之间的「差异」


🎯 一句话

一棵树很弱(上一章那个 91.8%), 但把几百棵弱树按正确方式组合起来,就是表格数据上至今难以撼动的最强模型 —— XGBoost / LightGBM 的全部秘密就在这。

📍 组合方式分三条完全不同的路:Bagging(并行,降方差)、Boosting(串行,降偏差)、 Stacking(分层)。⭐ 而它们组合的每一棵树,都是上一章那个 CART。


🌳 三、集成学习:三种组合方式

单棵树不稳定又易过拟合。把很多棵组合起来——但怎么组合,分成三条完全不同的路线:

① Bagging(并行,降方差)
  • 怎么组合:同一份数据 → 有放回抽样 3 次 → 分别训出树1 / 树2 / 树3 → 投票 / 平均
  • 代表:随机森林
💡 每棵树都在略微不同的数据上训练,它们的错误互相抵消 → 更稳
② Boosting(串行,降偏差)⭐ 最强
  • 怎么组合:树1 → 找出树1错在哪 → 树2 专门补这些错 → 找出还错在哪 → 树3 再补 → …
  • 代表:GBDT / XGBoost / LightGBM / CatBoost
💡 每棵新树都在「纠正前面所有树的残余错误」
③ Stacking(分层,学习怎么融合)
  • 怎么组合:树 + 线性 + 神经网络 → 各自的预测 → 再训一个模型学「怎么组合它们」
💡 Kaggle 冲榜常用,工程复杂

🔗 Kaggle 第 3 章模型融合 讲的就是 ③ 的各种实战技巧。


🌲 四、随机森林:Bagging + 双重随机

随机森林的两次随机,目的都是:让树彼此不一样随机 1:Bootstrap 抽样每棵树看到的数据样本不同随机 2:候选特征抽样每次分裂只能看随机 k 个特征树 A先看「面积」树 B先看「楼龄」树 C先看「位置」不同的树投票/平均,才会真的更稳
只做 Bootstrap 还不够:每棵树都可能先选到同一个最强特征。随机限制候选特征,才会强迫它们走出不同的判断路径。

💡 核心直觉:集成的收益来自成员之间的「差异」。全都一样的树,平均一百次还是那棵树。

优点:几乎不用调参、不易过拟合、能给特征重要性、可并行 缺点:精度通常略输 Boosting、模型体积大


🚀 五、GBDT:Boosting 的核心思想

这是本章最重要的部分——Kaggle 的主力算法。

它在做什么

真实房价 = 100 万:每棵新树只补“还差多少”树 1预测 80 万还差 20 万树 1 + 280 万+15 万差 5树 1 + 2 + 380 万+15 万+4每多一棵树,剩余误差就更小;最后的总预测 = 80 + 15 + 4 + … ≈ 100 万
这就是 Boosting:后面的树不从零猜房价,而是专门学习前面所有树还没解释掉的残差。

💡 人话:

每棵新树不预测答案本身,而是预测「前面所有树加起来还差多少」。 像考试订正错题:第一遍做完,专门针对错的部分再学一遍,反复迭代。

数学上:每棵新树拟合的是损失函数的负梯度(所以叫「梯度」提升)。 用 MSE 损失时,负梯度恰好就是残差——上面那个直觉是严格成立的。

三个关键超参(调参时主要动这三个)

参数 作用 经验值
n_estimators 树的数量 越多拟合越强 100–2000,配合早停
learning_rate 学习率 ⭐ 每棵树的贡献打几折 0.01–0.1。小 lr + 多树 = 更好但更慢
max_depth 树深 单棵树复杂度 3–8(比随机森林浅得多!)

🔑 最重要的一条调参直觉: learning_rate 和 n_estimators 是一对——学习率减半,树的数量大致要翻倍。 先固定 lr=0.1 调其他参数,最后再降 lr、加树数换取最后那点精度。

为什么 GBDT 的树要浅?

信息关系

随机森林:每棵树都想【独立解决问题】→要深(完全生长)
GBDT: 每棵树只需【纠正一点点错误】→要浅(深度 3-8)
GBDT 用浅树是故意的:单棵弱一点,才不会一步跨太大而过拟合

🚪 这里有一句话故意没讲完

「每棵新树拟合负梯度」——⭐ 负梯度只告诉你往哪个方向走,没告诉你该走多远。 GBDT 用 learning_rate 把步子统一压小,是绕开这个问题而不是解决它。

👉 04b · XGBoost 的推导:从负梯度到闭式解 该去的时候:要面试(「XGBoost 为什么用二阶泰勒展开」是必考)、要自定义损失函数、或者想知道 LightGBM 凭什么快、CatBoost 在防什么。 可以先不去的时候:只想会调参把分刷上去 —— 直接跳 Kaggle 第 1 章,那里有现成模板。 ⚠️ 但三巨头对比表在 04b,而且在那里它是推出来的不是背的。


🔨 动手:亲眼看集成的威力

from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import (RandomForestClassifier,
                              GradientBoostingClassifier, BaggingClassifier)
import numpy as np

X, y = load_breast_cancer(return_X_y=True)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3,
                                          random_state=42, stratify=y)

print(f"{'模型':<22}{'训练集':>9}{'测试集':>9}")
for name, m in [
    ("单棵决策树",        DecisionTreeClassifier(random_state=0)),
    ("Bagging(100棵)",   BaggingClassifier(n_estimators=100, random_state=0)),
    ("随机森林(100棵)",   RandomForestClassifier(n_estimators=100, random_state=0)),
    ("GBDT(100棵,深度3)", GradientBoostingClassifier(n_estimators=100,
                                                    max_depth=3, random_state=0)),
]:
    m.fit(X_tr, y_tr)
    print(f"{name:<22}{m.score(X_tr,y_tr):>8.1%}{m.score(X_te,y_te):>9.1%}")

print("\nGBDT:学习率与树数量的配合")
print(f"{'树数':<8}{'学习率':<10}{'测试集':>9}")
for n, lr in [(10,0.1),(50,0.1),(200,0.1),(500,0.1),(500,0.01)]:
    m = GradientBoostingClassifier(n_estimators=n, learning_rate=lr,
                                   max_depth=3, random_state=0).fit(X_tr, y_tr)
    print(f"{n:<8}{lr:<10}{m.score(X_te,y_te):>8.1%}")

print("\n特征重要性 Top5:")
rf = RandomForestClassifier(n_estimators=200, random_state=0).fit(X_tr, y_tr)
names = load_breast_cancer().feature_names
for i in np.argsort(-rf.feature_importances_)[:5]:
    print(f"  {names[i]:<25} {rf.feature_importances_[i]:.3f}")

实测结果:

① 多棵树,测试集更稳

同一份乳腺癌数据上的模型对比
模型训练集测试集读法
单棵决策树100.0%91.8%第 1 章那棵树:把训练集背下来了
Bagging(100 棵)100.0%94.2%比单棵树高 2.4 个百分点
随机森林(100 棵)100.0%94.2%随机化让多棵树不再长得一模一样
GBDT(100 棵、深度 3)100.0%94.2%后面的树专门修正前面的残差

② GBDT:学习率和树数要配套

学习率小,通常要用更多棵树补回来
树数学习率测试集读法
100.193.0%树还不够,来不及修完错误
2000.194.7%继续提升
5000.195.3%更多树仍然有收益
5000.0194.2%步子太小,500 棵仍然不够

③ 这次随机森林最看重的特征

特征重要性最高的 3 项
特征重要性
worst perimeter0.140
worst concave points0.132
worst radius0.115

💡 注意:所有集成模型训练集都是 100%,但测试集比单棵树高 2–3.5%。 训练集 100% 不等于过拟合——关键看测试集有没有跟着掉。


⚠️ 特征重要性的三个坑

树模型能给特征重要性,但别太当真:

坑 说明
偏向高基数特征 取值越多的特征(如 ID)越容易被选中分裂,重要性虚高
相关特征分摊 两个高度相关的特征会平分重要性,看起来都不重要
只反映训练集 不代表因果,也不代表在新数据上有用

⭐ 第一个坑的根就是第二节那件事:信息增益、增益率、基尼全都偏爱取值多的特征(用户 ID 的信息增益能到满分 1.000)。 CART 靠「只能二叉」把病压住了,但取值多 = 候选切分点多 = 被选中的机会多,这个偏向从来没被真正消除。

✅ 更可靠的做法:Permutation Importance(打乱某列看性能掉多少)或 SHAP。



🔗 和站内其他章的关系

相关的地方 根因在这
Kaggle 第 1、2 章大量用 LightGBM 就是本章的 GBDT
Kaggle 第 3 章模型融合 Stacking / Blending 的实战版
推荐算法第 7 章「用 GBDT 看特征重要性」 本章的特征重要性(连同它的坑)
推荐算法第 18 章的蒸馏 Boosting 的"用弱模型逼近强模型"思想有相通处

看完这一章,接着往哪走:

去哪 为什么要去那里
⭐ 04b · XGBoost 的推导 这一章故意没讲完的那半句在那里:负梯度只给方向不给步长,XGBoost 怎么用二阶泰勒展开把「下一棵树该怎么长」变成有闭式解的目标函数;三巨头对比表也在那里,而且是推出来的
04 · 决策树:怎么切一刀 ⚠️ 「特征重要性偏向高基数特征」这个坑的根在那一章第二节 —— 三代判据全都偏爱取值多的特征,CART 只是靠「只能二叉」压住
数学原理 · 08 偏差方差分解 本章说 Bagging 降方差、Boosting 降偏差,那两个词的严格定义和分解式在那里
第 16 章 · 特征工程基础 那里的 OOF 目标编码是「怎么用类别特征而不泄漏」的手工做法——树模型碰上高基数类别特征时的标准解
第 5 章 · 评估与过拟合 本章实测里「训练集 100% 但测试集只有 91.8%」到底算不算过拟合——判断标准在那一章

✅ 检查点

  1. Bagging 和 Boosting 的根本区别?各降低什么?
  2. 随机森林为什么要「随机选特征」?只做 Bootstrap 不够吗?
  3. GBDT 里每棵新树学的是什么?为什么树要比随机森林浅?
  4. learning_rate 和 n_estimators 是什么关系?调参该先动哪个?
  5. 实测里所有集成模型训练集都是 100%,这算过拟合吗?该看哪个数?
  6. 特征重要性有哪三个坑?其中「偏向高基数特征」的根在哪一章?
👀 答案
  1. Bagging 并行、每棵树独立在抽样数据上训练后投票,降方差;Boosting 串行、每棵新树纠正前面所有树的错误,降偏差。
  2. 不够。 只做 Bootstrap 的话,每棵树都可能先选到同一个最强特征分裂、长得都一样。⭐ 集成的收益全部来自成员之间的差异 —— 全都一样的树,平均一百次还是那棵树。
  3. 学的是前面所有树的残差(严格说是损失的负梯度)。浅是故意的:每棵树只需纠正一点点,深了就一步跨太大而过拟合,所以 3–8 层(比随机森林浅得多)。
  4. 是一对:学习率减半,树的数量大致要翻倍。⭐ 先固定 lr=0.1 调其他参数,最后再降 lr、加树数换取最后那点精度。
  5. 不算。训练集 100% 不等于过拟合,要看测试集有没有跟着掉——这里单棵树是 100.0% / 91.8%,三种集成都是 100.0% / 94.2%,测试集反而涨了 2.4 个点。
  6. 偏向高基数特征、相关特征分摊重要性、只反映训练集不代表因果。用 Permutation Importance 或 SHAP 更可靠。⭐ 第一个坑的根在 04 章第二节:三代判据全都偏爱取值多的特征,CART 只是靠「只能二叉」把它压住,没消除。

🛑 可以停在这里

到这里表格数据的主力你已经会用了:三条组合路线、随机森林的两次随机、GBDT 的三个旋钮, 外加特征重要性那三个坑。⭐ 只想把分刷上去的话,这些已经够了。

⚠️ 什么时候看下一页:你想知道「每棵新树拟合负梯度」后面那半句 —— 负梯度只给方向不给步长,而 XGBoost 怎么把它变成一个有闭式解的问题。

⚡ 走神救援

先记住这几件事

  • Bagging 让模型并行学习后汇总;Boosting 让后面的模型继续修正前面的不足。
  • GBDT 沿损失的负梯度方向拟合新树;平方损失下可理解为拟合残差。
  • 学习率控制每棵新树的贡献,树的数量与复杂度需要一起验证。
  • 先用验证集检查收益,再决定是否增加模型;模型更多并不自动更好。

下一节 👉 04b-XGBoost的推导.md

打卡记录保存在你的浏览器里,首页能看到总进度