GBDT(Gradient Boosting Decision Tree,梯度提升决策树)是机器学习中非常常用的一类模型,尤其适合表格数据任务。

它的名字看起来很长,但拆开以后并不神秘:

  • Gradient:沿着损失函数下降的方向修正模型。
  • Boosting:一轮一轮训练模型,后面的模型修正前面的错误。
  • Decision Tree:每一轮加入的基模型通常是一棵回归树。

一句话概括:

GBDT 不是一次训练一棵很大的树,而是一棵树接一棵树地补前面模型的错误。

GBDT 逐轮修正示意图

1. 为什么需要 GBDT

单棵决策树有两个明显问题:

  • 树太浅,模型表达能力不够,容易欠拟合。
  • 树太深,容易把训练数据记得太死,导致过拟合。

GBDT 的思路不是训练一棵特别复杂的树,而是训练很多棵相对简单的树。

每一棵树只做一件事:

修正当前模型还没预测好的部分

这样模型可以逐步变强,同时通过学习率、树深度、树数量等参数控制复杂度。

2. 从一个房价例子理解 GBDT

假设我们要预测 3 套房子的价格:

房子 面积 房龄 真实价格
A 70 平 15 年 100 万
B 100 平 8 年 160 万
C 130 平 3 年 200 万

GBDT 一开始不会直接训练复杂模型,而是先给一个很粗的初始预测。

对于平方误差损失,常见初始预测就是所有标签的平均值:

$$
F_0(x)=\bar{y}=\frac{100+160+200}{3}=153.3
$$

也就是说,一开始模型对所有房子都预测:

153.3 万

显然这个预测很粗糙。于是我们计算残差:

$$
r_i=y_i-F_0(x_i)
$$

房子 真实价格 $y$ 当前预测 $F_0$ 残差 $r=y-F_0$
A 100 153.3 -53.3
B 160 153.3 6.7
C 200 153.3 46.7

残差的含义很直观:

  • A 的残差是 -53.3,说明当前预测太高了,要往下修正。
  • B 的残差是 6.7,说明当前预测已经差不多。
  • C 的残差是 46.7,说明当前预测太低了,要往上修正。

第一棵树学习的目标不是房价本身,而是这些残差。

3. 第一棵树如何修正预测

假设第一棵树 $h_1(x)$ 学到了一个简单规则:

如果 面积 <= 90 平:
    输出 -40
否则:
    输出 35

这表示:

  • 小面积房子当前预测偏高,需要减一点。
  • 大面积房子当前预测偏低,需要加一点。

如果学习率 $\eta=0.5$,GBDT 的更新公式是:

$$
F_1(x)=F_0(x)+\eta h_1(x)
$$

代入每套房子:

房子 $F_0(x)$ $h_1(x)$ $\eta h_1(x)$ 新预测 $F_1(x)$
A 153.3 -40 -20 133.3
B 153.3 35 17.5 170.8
C 153.3 35 17.5 170.8

可以看到:

  • A 从 153.3 降到 133.3,更接近真实值 100。
  • C 从 153.3 升到 170.8,更接近真实值 200。
  • B 被修正得有点过头,这也没关系,下一轮还会继续修正。

接着计算新的残差:

$$
r_i^{(2)}=y_i-F_1(x_i)
$$

房子 真实价格 当前预测 $F_1$ 新残差
A 100 133.3 -33.3
B 160 170.8 -10.8
C 200 170.8 29.2

第二棵树继续学习这些新残差。

所以 GBDT 的训练过程可以理解为:

先给一个粗略预测
    -> 计算当前还差多少
    -> 训练一棵树去拟合这个差距
    -> 用学习率控制修正幅度
    -> 更新预测
    -> 再计算新的差距
    -> 继续训练下一棵树

4. GBDT 的加法模型形式

GBDT 最终得到的不是一棵树,而是很多棵树的累加:

$$
F_T(x)=F_0(x)+\eta\sum_{t=1}^{T}h_t(x)
$$

其中:

  • $F_0(x)$ 是初始预测。
  • $h_t(x)$ 是第 $t$ 棵树。
  • $T$ 是树的数量。
  • $\eta$ 是学习率。

如果每棵树都输出一个修正值,那么最终预测就是:

初始预测 + 第 1 棵树的修正 + 第 2 棵树的修正 + ... + 第 T 棵树的修正

例如某套房子的预测过程是:

初始预测:153.3
第 1 棵树修正:-20.0
第 2 棵树修正:-12.5
第 3 棵树修正:-6.0

最终预测为:

$$
\hat{y}=153.3-20.0-12.5-6.0=114.8
$$

这就是 GBDT 的加法模型思想。

5. 为什么叫“梯度”提升

前面用平方误差时,我们一直说“拟合残差”。但 GBDT 不只适用于平方误差。

更一般地说,GBDT 每一轮拟合的是损失函数的负梯度。

假设训练目标是最小化:

$$
\sum_{i=1}^{n}L(y_i,F(x_i))
$$

第 $t$ 轮时,当前模型是 $F_{t-1}(x)$。对每个样本,计算负梯度:

$$
r_i^{(t)}=
-\left[
\frac{\partial L(y_i,F(x_i))}{\partial F(x_i)}
\right]{F=F{t-1}}
$$

然后训练一棵新的回归树 $h_t(x)$,让它拟合这些 $r_i^{(t)}$。

这里的 $r_i^{(t)}$ 可以理解为:

当前模型在第 i 个样本上,最应该往哪个方向修正

所以 GBDT 的“梯度”不是说树本身能求导,而是说模型每一轮沿着损失函数下降的方向加一棵树。

6. 平方误差下:负梯度就是残差

回归任务中,常用平方误差:

$$
L(y,F(x))=\frac{1}{2}(y-F(x))^2
$$

对 $F(x)$ 求导:

$$
\frac{\partial L}{\partial F(x)}=F(x)-y
$$

负梯度为:

$$
-\frac{\partial L}{\partial F(x)}=y-F(x)
$$

而 $y-F(x)$ 正好就是残差。

所以在平方误差下:

拟合负梯度 = 拟合残差

这也是为什么很多入门材料会先用“拟合残差”解释 GBDT。这个说法没错,但它只是平方误差下的特殊情况。

7. 一棵 GBDT 树的叶子输出什么

在 GBDT 中,每一轮训练的是一棵回归树。它会把样本分到不同叶子节点,然后每个叶子输出一个修正值。

GBDT 单棵树拟合残差示意图

假设某一轮中有 5 个样本的残差:

样本 残差
A -50
B -40
C -10
D 30
E 45

一棵回归树可能把它们分成两个叶子:

叶子 1:A、B、C
叶子 2:D、E

对于平方误差,叶子输出通常取该叶子中残差的平均值。

叶子 1:

$$
\gamma_1=\frac{-50-40-10}{3}=-33.3
$$

叶子 2:

$$
\gamma_2=\frac{30+45}{2}=37.5
$$

如果学习率 $\eta=0.1$,那么落到叶子 1 的样本会被修正:

$$
0.1\times(-33.3)=-3.33
$$

落到叶子 2 的样本会被修正:

$$
0.1\times37.5=3.75
$$

这说明 GBDT 的每棵树不是给出最终答案,而是给出一小步修正。

8. 分类任务中的 GBDT

GBDT 不只能做回归,也能做分类。

二分类中,模型通常不直接输出类别,而是输出一个分数 $F(x)$,再通过 Sigmoid 函数转成概率:

$$
p(x)=\frac{1}{1+e^{-F(x)}}
$$

如果 $p(x)\ge 0.5$,预测为正类;否则预测为负类。

常用损失函数是对数损失:

$$
L(y,F(x))=-[y\log p(x)+(1-y)\log(1-p(x))]
$$

其中 $y\in{0,1}$。

对这个损失求负梯度,可以得到:

$$
r_i = y_i - p_i
$$

这也很直观:

  • 如果真实 $y=1$,但模型预测概率 $p=0.2$,则 $r=0.8$,说明要大幅提高正类分数。
  • 如果真实 $y=0$,但模型预测概率 $p=0.9$,则 $r=-0.9$,说明要大幅降低正类分数。

举个例子:

学生 是否通过 $y$ 当前预测概率 $p$ 负梯度 $r=y-p$
A 1 0.80 0.20
B 1 0.30 0.70
C 0 0.60 -0.60
D 0 0.10 -0.10

下一棵树会重点修正 B 和 C,因为它们的负梯度绝对值更大,说明当前模型错得更明显。

9. 学习率和树数量

GBDT 的更新公式通常写成:

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

其中 $\eta$ 是学习率。

学习率越小,每棵树的修正幅度越小。这样训练更稳,但通常需要更多树。

例如同样一棵树输出修正值 $h_t(x)=40$:

  • 如果 $\eta=1$,本轮直接加 40。
  • 如果 $\eta=0.1$,本轮只加 4。
  • 如果 $\eta=0.01$,本轮只加 0.4。

所以常见经验是:

小学习率 + 多棵树

例如:

learning_rate = 0.05
n_estimators = 300

通常比:

learning_rate = 0.5
n_estimators = 30

更稳,但训练成本也更高。

10. GBDT 的重要参数

使用 GBDT 时,常见参数包括:

参数 含义 影响
n_estimators 树的数量 太少容易欠拟合,太多可能过拟合
learning_rate 学习率 控制每棵树的修正幅度
max_depth 单棵树最大深度 控制每棵树复杂度
min_samples_leaf 叶子节点最少样本数 防止叶子过小
subsample 每轮采样比例 小于 1 时类似随机梯度提升,可降低过拟合
loss 损失函数 决定负梯度如何计算

调参时可以先抓住三个核心:

  1. learning_rate
  2. n_estimators
  3. max_depth

树越深,单棵树越强,也越容易过拟合。GBDT 中的树通常不需要太深,很多任务中深度 3 到 6 已经能工作得不错。

11. sklearn 中训练 GBDT 回归模型

下面用一个简单的回归例子训练 GBDT。

from sklearn.datasets import make_regression
from sklearn.ensemble import GradientBoostingRegressor
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split

# 构造一个回归数据集
X, y = make_regression(
    n_samples=300,
    n_features=6,
    noise=15,
    random_state=42,
)

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
)

model = GradientBoostingRegressor(
    n_estimators=200,
    learning_rate=0.05,
    max_depth=3,
    random_state=42,
)

model.fit(X_train, y_train)

y_pred = model.predict(X_test)

print("MSE:", mean_squared_error(y_test, y_pred))

这段代码对应前面的公式:

先初始化预测
    -> 每一轮训练一棵回归树
    -> 新树拟合当前负梯度
    -> 更新整体模型

实际项目中,GBDT 很常用于房价预测、销量预测、风险评分、用户价值预测等表格数据回归任务。

12. sklearn 中训练 GBDT 分类模型

下面用鸢尾花数据集训练一个分类模型。

from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
from sklearn.model_selection import train_test_split

iris = load_iris()
X = iris.data
y = iris.target

X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

model = GradientBoostingClassifier(
    n_estimators=100,
    learning_rate=0.05,
    max_depth=3,
    random_state=42,
)

model.fit(X_train, y_train)

y_pred = model.predict(X_test)

print(classification_report(y_test, y_pred, target_names=iris.target_names))

分类任务中,GBDT 常用于:

  • 用户是否会流失。
  • 是否为欺诈交易。
  • 是否点击广告。
  • 是否通过考试。
  • 商品是否会被购买。

如果类别不平衡,不建议只看准确率,可以结合精确率、召回率、F1、AUC 等指标。

13. 为什么会出现 GBDT 的变体

原始 GBDT 思想很清楚,但真实工程中会遇到一些问题:

  • 数据量大时,训练速度慢。
  • 特征很多时,寻找最佳分裂很耗时。
  • 容易过拟合,需要更好的正则化。
  • 类别特征处理麻烦。
  • 缺失值、稀疏特征、大规模数据需要更好的工程实现。

于是出现了很多 GBDT 变体。

GBDT 变体对比示意图

14. XGBoost:加入二阶梯度和正则化

XGBoost 可以看成是 GBDT 的一个强工程增强版。

它的目标函数通常写成:

$$
Obj=\sum_{i=1}^{n}L(y_i,\hat{y}i)+\sum{t=1}^{T}\Omega(f_t)
$$

前半部分是训练损失,后半部分是树的复杂度惩罚。

常见正则项为:

$$
\Omega(f)=\gamma K+\frac{1}{2}\lambda\sum_{j=1}^{K}w_j^2
$$

其中:

  • $K$ 是叶子节点数量。
  • $w_j$ 是第 $j$ 个叶子的输出值。
  • $\gamma$ 惩罚叶子数量,防止树长得太复杂。
  • $\lambda$ 惩罚叶子权重,防止叶子输出过大。

XGBoost 的一个重要特点是使用二阶泰勒展开。对第 $t$ 轮新增树 $f_t$,目标函数近似为:

$$
Obj^{(t)}\approx
\sum_{i=1}^{n}
\left[
g_i f_t(x_i)+\frac{1}{2}h_i f_t^2(x_i)
\right]
+\Omega(f_t)
$$

其中:

$$
g_i=\frac{\partial L(y_i,\hat{y}_i)}{\partial \hat{y}_i}
$$

$$
h_i=\frac{\partial^2 L(y_i,\hat{y}_i)}{\partial \hat{y}_i^2}
$$

也就是说,XGBoost 不只看一阶梯度,还看二阶梯度,能更精细地估计下一步怎么修正。

14.1 XGBoost 的实际应用

假设做信用风险预测,要判断一个用户是否可能违约。特征包括:

年龄、收入、负债率、历史逾期次数、消费行为、还款记录

XGBoost 会不断加树,每一棵树都修正当前模型对违约概率的判断。同时正则项会限制树不要太复杂,降低过拟合风险。

因此它常用于:

  • 风控评分。
  • 广告点击率预估。
  • 用户流失预测。
  • 比赛类表格数据任务。

15. LightGBM:更快的大规模 GBDT

LightGBM 的重点是快,尤其适合大规模表格数据。

它有几个典型思想:

15.1 直方图算法

传统 GBDT 找分裂点时,可能会枚举很多连续取值。LightGBM 会先把连续特征分桶。

例如“年龄”原本有很多取值:

18, 19, 20, 21, ..., 60

可以分成几个桶:

18-25, 26-35, 36-45, 46-60

这样找分裂点时,不用遍历每个具体数值,而是在桶上搜索,速度会快很多。

15.2 Leaf-wise 生长

普通树常见做法是 level-wise,也就是一层一层长。

LightGBM 使用 leaf-wise:每次优先选择能带来最大损失下降的叶子继续分裂。

直观理解:

哪里错得最严重,就优先细分哪里

这样通常能更快降低损失,但也更容易过拟合,所以常配合 num_leavesmax_depth 控制复杂度。

15.3 GOSS 和 EFB

LightGBM 还引入了 GOSS 和 EFB:

  • GOSS:保留梯度大的样本,随机采样梯度小的样本。
  • EFB:把互斥的稀疏特征合并,减少特征数量。

梯度大的样本通常表示当前模型还没学好,保留它们可以更高效地训练。

LightGBM 常用于:

  • 大规模点击率预估。
  • 推荐系统排序。
  • 金融风控。
  • 海量表格数据建模。

16. CatBoost:更擅长处理类别特征

很多表格数据里有大量类别特征,例如:

城市、职业、商品类别、商家 ID、用户等级

普通 GBDT 往往需要先手动做 One-Hot 编码、目标编码等处理。CatBoost 的优势之一就是对类别特征更友好。

16.1 类别特征的目标统计

例如有一个特征“城市”,标签是“是否购买”。

可以计算每个城市的购买率:

城市 购买率
北京 0.72
上海 0.68
深圳 0.75

然后用这个统计值代替原始类别。

但这里有一个风险:如果直接用全量数据计算购买率,某个样本自己的标签会参与编码自己,产生目标泄漏。

CatBoost 使用 Ordered Target Statistics 来降低这种泄漏风险。直观理解是:

给当前样本做类别编码时,只使用它之前样本的标签统计,不提前偷看当前样本标签。

16.2 Ordered Boosting

CatBoost 还使用 Ordered Boosting 来减少预测偏移。它通过有序训练方式,让模型在训练时尽量模拟“面对新样本”的状态。

CatBoost 常用于:

  • 类别特征很多的业务数据。
  • 电商、广告、推荐系统。
  • 不想手动做大量类别特征编码的任务。

17. GBDT、XGBoost、LightGBM、CatBoost 对比

模型 核心特点 适合场景
GBDT 原始梯度提升树,思想清晰 学习原理、中小规模任务
XGBoost 二阶梯度、正则化、缺失值处理强 通用表格数据、比赛、风控
LightGBM 训练快、内存低、适合大数据 大规模数据、推荐、CTR
CatBoost 类别特征处理友好 类别变量多的业务数据

简单选择建议:

  1. 学原理:先学 GBDT。
  2. 做通用表格任务:优先试 XGBoost 或 LightGBM。
  3. 数据量很大:优先试 LightGBM。
  4. 类别特征很多:优先试 CatBoost。

18. GBDT 的优缺点

优点

  • 对表格数据效果很强。
  • 可以处理非线性关系。
  • 不太依赖特征缩放。
  • 能做回归,也能做分类。
  • 通过逐步修正错误,模型表达能力强。

缺点

  • 训练通常比单棵树慢。
  • 参数较多,需要调参。
  • 对噪声和异常值可能比较敏感。
  • 树很多时,可解释性下降。
  • 原始 GBDT 对高维稀疏特征不一定最高效。

19. 实践建议

使用 GBDT 类模型时,可以注意:

  1. 先划分训练集、验证集、测试集,避免数据泄漏。
  2. 用较小学习率配合较多树,例如 learning_rate=0.05
  3. 控制树深度,不要让单棵树太复杂。
  4. 使用早停,验证集效果不再提升时停止训练。
  5. 类别不平衡时,不要只看准确率。
  6. 对异常值和脏数据要谨慎,Boosting 容易关注难样本。

如果使用 XGBoost、LightGBM、CatBoost,一般都可以设置 early stopping:

如果验证集指标连续多轮没有提升,就停止加树

这能减少过拟合,也能节省训练时间。

20. 总结

GBDT 的核心可以概括为三句话:

  • 当前模型先给出一个预测。
  • 根据损失函数计算每个样本应该如何修正。
  • 训练一棵新树去拟合这个修正方向,并把它加到整体模型里。

在平方误差下,这个修正方向就是残差;在一般损失函数下,这个修正方向是负梯度。

理解 GBDT 时,可以抓住这条主线:

初始预测 -> 计算负梯度 -> 训练回归树 -> 更新模型 -> 重复

XGBoost、LightGBM、CatBoost 都是在这条主线上做工程增强:XGBoost 加入更强的正则化和二阶信息,LightGBM 追求大规模训练效率,CatBoost 更擅长处理类别特征。

掌握 GBDT 之后,再看这些变体,就不会觉得它们是完全陌生的新算法,而是同一个思想在不同工程场景下的改进版本。