梯度提升树(GBDT)回归原理

梯度提升树(GBDT,Gradient Boosting Decision Tree)回归是一种集成学习方法,它通过逐步构建多个决策树来优化预测结果,尤其适用于回归问题。GBDT 通过“加法模型”逐步提高模型的预测能力,每一步都在减少前一步模型的误差。

1. 预测过程

GBDT 的回归预测过程为:初始值 + 每棵决策树的输出结果 * 学习率,如下公式所示:

其中:

  • \( \hat{y}(x) \) 表示模型对输入 \( x \) 的最终预测值
  • \( \hat{y}_{0}(x) \) 是初始值,可以理解为初步的预测分数
  • \( f_{m}(x) \) 是第 \( m \) 棵树的输出分数
  • \( \eta \) 表示学习率,控制每棵树的贡献
  • \( M \) 表示 GBDT 中回归决策树的数量

假设:我们基于训练数据得到的 GBDT 回归模型如下,我们需要对新数据 [0.64768854, -0.1382643, 0.49671415] 进行预测:

上面的三棵回归决策树构成了强学习器 GBDT。
首先计算初始值,对于平方误差(Squared Error),初始值为训练数据的均值,即:mean(y) = -8.09

然后将新数据分别送入到不同的决策树中得到预测值:

  • 第一个决策树输出值:31.51
  • 第二个决策树输出值:28.36
  • 第三个决策树输出值:19.47

假设学习率为 0.1,则最终输出值:-8.09 + (31.51 + 28.36 + 19.47) * 0.1 = -0.155。下面为具体的代码计算过程:

from sklearn.ensemble import GradientBoostingRegressor
from sklearn.datasets import make_regression
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import plot_tree

# 生成随机数据
np.random.seed(0)
x, y = make_regression(n_samples=10,
                       n_features=3,
                       random_state=42)

# 训练分类模型
gbdt = GradientBoostingRegressor(n_estimators=3,
                                 max_depth=2,
                                 criterion='squared_error',
                                 loss='squared_error')
gbdt.fit(x, y)

# 可视化 GBDT
for estimator in gbdt.estimators_:
    plt.figure(figsize=(13, 8))
    plot_tree(estimator[0], filled=True, rounded=True, fontsize=14, precision=2)
    plt.show()

# 新数据预测
new_x, new_y = make_regression(n_samples=1, n_features=3, random_state=42)
print('输入数据:', new_x, new_y)

# 直接计算类别概率
print('直接计算:', gbdt.predict(new_x)[0])

# 分布计算类别概率
def test():
    # 1. 初始值
    total_score = np.mean(y)  # squared_error,使用均值
    # total_score = np.median(y)  # absolute_error,使用中位数
    # total_score = np.median(y)  # huber,使用中位数
    # total_score = np.percentile(y, 90)  # quantile,0.9 分位数,alpha 参数指定

    # 2. 累加每个树的得分
    learning_rate = 0.1
    for estimator in gbdt.estimators_:
        # 每棵树计算得分
        score = estimator[0].predict(new_x)
        # 累加每棵树得分
        total_score += score[0] * learning_rate

    # 3. 将得分输出概率
    print('手动计算:', total_score)


if __name__ == '__main__':
    test()

程序输出结果:

输入数据: [[ 0.64768854 -0.1382643   0.49671415]] 9.35482833533384
直接计算: -0.15512286528967145
手动计算: -0.15512286528967145

2. 训练过程

我们以 criterion=’squared_error’ 和 loss=’squared_error’ 为例,训练数据如下:

特征1特征2特征3目标值
-0.908024081.46564877-1.4123037-106.40638687
-0.54438272-1.150993580.11092259-46.41270092
0.24196227-1.72491783-1.91328024-88.70824211
0.37569802-0.29169375-0.60063869-4.29054154
1.52302986-0.23413696-0.2341533791.04704754
0.54256004-0.46572975-0.4634176911.04262105
0.496714150.64768854-0.138264335.80536172
-0.562287530.31424733-1.01283112-79.21856515
1.57921282-0.469474390.76743473136.10440487
-0.2257763-1.424748190.0675282-29.86346474

接下来,演示训练过程。根据下面 GBDT 公式:

可知训练过程需要做两件事:

  • 计算初值
  • 训练多个回归决策树

对于初始值,使用不同的损失函数,初始值的计算方式也有所不同,例如:使用 squared_error 损失函数时,会使用训练数据的均值作为初值。使用 absolute_error 或者 huber 时,则使用训练数据的中位数作为初值。我们这里使用的是 squared_error,所以初始值 \( \hat{y}_{0}(x) = mean(y) = -8.09 \)。

接下来,我们开始训练 \( M=3 \) 个回归决策树,每个回归决策树训练步骤如下:

  • 根据损失函数计算残差
  • 以残差作为目标值训练回归决策树
  • 修正叶子节点的输出值(默认是叶子节点的样本均值,这里根据不同的损失函数进行修正)

我们这里使用 squared_error,其残差(负梯度)计算公式如下:

其中,\( y_{i} \) 为样本真实目标值,\( F(x_{i}) \) 为到当前回归决策树的 GBDT 输出值。

特征1特征2特征3目标值残差
-0.908024081.46564877-1.4123037-106.40638687-98.31638687
-0.54438272-1.150993580.11092259-46.41270092-38.32270092
0.24196227-1.72491783-1.91328024-88.70824211-80.61824211
0.37569802-0.29169375-0.60063869-4.290541543.79945846
1.52302986-0.23413696-0.2341533791.0470475499.13704754
0.54256004-0.46572975-0.4634176911.0426210519.13262105
0.496714150.64768854-0.138264335.8053617243.89536172
-0.562287530.31424733-1.01283112-79.21856515-71.12856515
1.57921282-0.469474390.76743473136.10440487144.19440487
-0.2257763-1.424748190.0675282-29.86346474-21.77346474

使用上面的数据进行训练,这里注意,训练拟合的目标值是残差,而不是真实值。假设 max_depth=2,使用 criterion 指定的方法计算所有候选切分点,并进行树的分裂,训练结束后,得到如下回归决策树:

最后一步进行叶子节点值的修正,对于 squared_error 损失函数,叶子节点不需要额外的修正。注意:对于其他的损失函数,叶子节点值并不是简单得样本均值,而是经过一定的方法进行修正,这里就不深入探讨这一部分了。

特征1特征2特征3目标值当前输出值累计输出值
-0.908024081.46564877-1.4123037-106.40638687-83.35435143-16.42548176
-0.54438272-1.150993580.11092259-46.41270092-18.76552245-9.966598861
0.24196227-1.72491783-1.91328024-88.70824211-83.35435143-16.42548176
0.37569802-0.29169375-0.60063869-4.29054154-18.76552245-9.966598861
1.52302986-0.23413696-0.2341533791.04704754121.665772824.0765306665
0.54256004-0.46572975-0.4634176911.0426210531.514038-4.938642815
0.496714150.64768854-0.138264335.8053617231.514038-4.938642815
-0.562287530.31424733-1.01283112-79.21856515-83.35435143-16.42548176
1.57921282-0.469474390.76743473136.10440487121.665772824.0765306665
-0.2257763-1.424748190.0675282-29.86346474-18.76552245-9.966598861

上表中,累计输出值,是到当前决策树所有决策树的输出 * 学习率 + 初始值。接下来,训练第二棵决策树,还是先计算残差:

特征1特征2特征3目标值残差
-0.908024081.46564877-1.4123037-106.40638687-89.9809051156
-0.54438272-1.150993580.11092259-46.41270092-36.4461020608
0.24196227-1.72491783-1.91328024-88.70824211-72.2827603483
0.37569802-0.29169375-0.60063869-4.290541545.67605732113
1.52302986-0.23413696-0.2341533791.0470475486.9705168713
0.54256004-0.46572975-0.4634176911.0426210515.98126386669
0.496714150.64768854-0.138264335.8053617240.7440045344
-0.562287530.31424733-1.01283112-79.21856515-62.79308338979
1.57921282-0.469474390.76743473136.10440487132.0278742051
-0.2257763-1.424748190.0675282-29.86346474-19.8968658841

这里残差计算就是原始的目标值 – 累计输出值,有了残差,继续训练第二个回归决策树。至此,大家应该能发现了,GBDT 的训练过程就是不停的基于残差方向进行训练,目标是减少 GBDT 预测的误差,而且随着训练的回归决策树越来越多,预测的精度也会越来越高。

但是,需要注意的是,训练的决策树并不是越多越好,更多的决策树能够带来较小的训练误差,但是也可能会导致过度拟合训练数据,引起较大的泛化误差。

另外,我们在训练过程中,引入了学习率。学习率降低了训练时,每棵树对预测结果的贡献,从而使得需要训练更多的回归决策树。所以,学习率是用来平衡每棵树的贡献和决策树数量的一个参数。

未经允许不得转载:一亩三分地 » 梯度提升树(GBDT)回归原理
评论 (0)

7 + 7 =