1. 残差(Residual)

在学习决策提升数之前,我们需要先了解一个基本的概念——残差。残差是预测值和真实值之间的误差。
例如,我们要预测一个学生A的成绩,预测值为70,真实值为50,那么残差就是80-50=30。
我们可以很容易构建一个残差树:

  • 满分100分,学生A成绩70分
  • 第一次预测:取满分中值50分,残差为70-50=20
  • 第二次预测:根据上一轮残差20,取残差中值10分,残差为20-10=10
  • 第三次预测:根据上一轮残差10,取残差中值5分,残差为10-5=5
  • 第四次预测:根据上一轮残差5,取残差中值2分,残差为5-2=3
  • 第五次预测:根据上一轮残差3,取残差中值1分,残差为3-1=2
  • 第六次预测:根据上一轮残差2,取残差中值1分,残差为2-1=1
  • 我们可以往复预测,直到残差为0,也可以设定一个阈值,比如现在我们设定阈值为1,当残差小于等于1时,我们停止预测。
  • 将以上预测结果相加,我们得到:50+10+5+2+1+1=69分,作为我们的最终预测结果。

我们可以看到通过多轮残差提升,可以得到一个比较精确的决策树,但是很明显,它是过于拟合且难以处理复杂问题。
基于集成学习的思想,我们可以进行改进,通过集成多个残差树,进行改进集成多个残差树来提升模型的表现。
这种方法称为梯度提升决策树(GBDT)。GBDT通过将多个弱学习器(即简单的决策树)集成在一起,从而形成一个强大的预测模型。

2. GBDT原理

GBDT 是一种迭代的优化算法,它通过逐步减少预测误差来提升模型性能。具体来说,GBDT 的工作流程如下:

  1. 初始模型:首先,使用一个简单的决策树模型来进行初始预测。这个模型通常是通过最小化损失函数来构建的。例如,对于回归问题,初始模型可能是一个常数模型,使得损失函数(如均方误差)最小化。
  2. 计算残差:计算初始模型的残差,即预测值与真实值之间的差异。这些残差将作为下一轮学习的目标。
  3. 构建新树:使用残差作为目标变量,构建一个新的决策树。这个新树的目的是拟合残差,从而进一步减少预测误差。
  4. 更新模型:将新树的预测结果与当前模型的预测结果结合起来,形成一个新的组合模型。通常,结合方法是通过加权和的方式,其中新树的预测结果乘以一个学习率参数,然后与当前模型的预测结果相加。
  5. 迭代更新:重复步骤 2-4,构建多个决策树,每次都在减少残差的基础上进行改进。迭代次数(即树的数量)和学习率是 GBDT 的超参数,需要通过交叉验证等方法进行调优。

具体数学公式如下:

  1. 损失函数:设定要最小化的损失函数 L(y, F(x)),其中 y 是真实值,F(x) 是模型的预测值。

  2. 初始化模型:使用常数值初始化模型,以最小化损失函数。通常选取所有目标值的平均值。

    F_0(x) = \arg\min_c \sum_{i=1}^N L(y_i, c)
  3. 迭代训练:在每一轮迭代中,执行以下步骤:

    • 计算残差:计算当前模型的负梯度(对于回归问题就是残差)。

      r_{im} = -\left[ \frac{\partial L(y_i, F(x_i))}{\partial F(x_i)} \right]_{F(x)=F_{m-1}(x)}
    • 拟合残差:使用残差作为目标变量,训练一个新的决策树。

      h_m(x) = \arg\min_{h} \sum_{i=1}^N (r_{im} - h(x_i))^2
    • 更新模型:将新决策树的输出乘以学习率后加到当前模型上。

      F_m(x) = F_{m-1}(x) + \eta h_m(x)

      其中 \eta 是学习率,用于控制每次更新的幅度。

3. GBDT构建

假设我们有一个简单的回归数据集:

x y
1 2
2 3
3 6
4 8

步骤 1:初始化模型

使用平方误差损失函数 L(y, F(x)) = (y - F(x))^2 计算所有目标值的平均值作为初始模型:

F_0(x) = \frac{2 + 3 + 6 + 8}{4} = 4.75

步骤 2:第一轮迭代

  • 计算残差

    r_{i1} = y_i - F_0(x_i)
    x y F_0(x) r_{i1}
    1 2 4.75 -2.75
    2 3 4.75 -1.75
    3 6 4.75 1.25
    4 8 4.75 3.25
  • 拟合残差:训练一个决策树来拟合残差。

    假设训练的树的输出如下(这一步,可以通过对每一个节点进行分裂,通过计算残差均值,选取最佳分裂点。为了简化,我们假设输出为残差的平均值):

    h_1(x) = \begin{cases} -2.25 & \text{if } x \leq 2 \\ 2.25 & \text{if } x > 2 \end{cases}

    计算得到的值分别为:

    • 对于 x \leq 2 的部分,平均残差为:
      \frac{-2.75 + (-1.75)}{2} = -2.25
    • 对于 x > 2 的部分,平均残差为:
      \frac{1.25 + 3.25}{2} = 2.25
  • 更新模型

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

    设定学习率 \eta = 0.1

    x F_0(x) h_1(x) \eta h_1(x) F_1(x)
    1 4.75 -2.25 -0.225 4.525
    2 4.75 -2.25 -0.225 4.525
    3 4.75 2.25 0.225 4.975
    4 4.75 2.25 0.225 4.975

步骤 3:重复迭代
在这一步,我们将进行迭代,重复步骤 2 和步骤 3,直到残差小于等于阈值或迭代次数达到上限。
但出于简化考虑,我们假设迭代次数为2进行演示。

  • 计算残差

    r_{i2} = y_i - F_1(x_i)
    x y F_1(x) r_{i2}
    1 2 4.525 -2.525
    2 3 4.525 -1.525
    3 6 4.975 1.025
    4 8 4.975 3.025
  • 拟合新的残差:训练新的决策树来拟合新的残差。

    假设新的树的输出如下:

    h_2(x) = \begin{cases} -2.025 & \text{if } x \leq 2 \\ 2.025 & \text{if } x > 2 \end{cases}

    计算得到的值分别为:

    • 对于 x \leq 2 的部分,平均残差为:
      \frac{-2.525 + (-1.525)}{2} = -2.025
    • 对于 x > 2 的部分,平均残差为:
      \frac{1.025 + 3.025}{2} = 2.025
  • 更新模型

    F_2(x) = F_1(x) + \eta h_2(x)
    x F_1(x) h_2(x) \eta h_2(x) F_2(x)
    1 4.525 -2.025 -0.2025 4.3225
    2 4.525 -2.025 -0.2025 4.3225
    3 4.975 2.025 0.2025 5.1775
    4 4.975 2.025 0.2025 5.1775

步骤 4:验证模型

在完成两轮迭代后,我们可以通过验证数据集来验证模型的性能。假设我们有一个验证数据集:

x y
1.5 2.5
2.5 4.0
3.5 6.5
4.5 7.5

使用更新后的模型 F_2(x) 来进行预测:

x F_2(x) 预测\hat{y}
1.5 4.3225 4.3225
2.5 4.3225 4.3225
3.5 5.1775 5.1775
4.5 5.1775 5.1775

计算预测误差:

\sum_{i=1}^N (y_i - \hat{y}_i)^2
x y 预测\hat{y} 误差(y - \hat{y})^2
1.5 2.5 4.3225 (2.5 - 4.3225)^2 = 3.33
2.5 4.0 4.3225 (4.0 - 4.3225)^2 = 0.10
3.5 6.5 5.1775 (6.5 - 5.1775)^2 = 1.75
4.5 7.5 5.1775 (7.5 - 5.1775)^2 = 5.39
\text{总误差} = 3.33 + 0.10 + 1.75 + 5.39 = 10.57

通过上述步骤,我们已经进行了一次完整的GBDT构建,由于数据的简单性,以及迭代的简化,我们并没有得到很理想的结果。
但我们应该了解并关注,GBDT的构建过程需要多次迭代,直到残差小于阈值或迭代次数达到上限,从而实现理想的结果。

4. GBDT适用场景

要了解GBDT的适用场景,需要了解其优缺点:
优点

  • 高准确性
    GBDT 在处理各种任务(如分类、回归)时表现出色,通常能够提供高准确性的预测。
  • 良好的泛化能力
    通过逐步减少误差,GBDT 能够有效地提高模型的泛化能力,避免过拟合。
  • 处理非线性关系
    GBDT 能够捕捉数据中的复杂非线性关系,适用于多种复杂场景。
  • 特征重要性评估
    GBDT 提供了特征重要性评估功能,可以帮助理解哪些特征对模型的预测结果贡献最大。
  • 鲁棒性
    对缺失值和异常值具有一定的鲁棒性,模型能够较好地处理这些问题。

缺点

  • 训练时间长
    由于需要逐步训练多棵树,GBDT 的训练过程可能较慢,尤其在大规模数据集上。
  • 难以并行化
    传统 GBDT 的训练过程是串行的,每棵树的训练依赖于前一棵树的结果,难以实现并行计算。
  • 复杂的超参数调优
    GBDT 包含多个超参数(如学习率、树的数量、树的深度等),需要仔细调优才能获得最佳性能。
  • 内存消耗大
    GBDT 在训练过程中需要存储大量中间结果,对内存消耗较大。

基于优缺点,GBDT通常适用于以下场景:

  1. 分类问题

    • 如垃圾邮件分类、客户流失预测、欺诈检测等。
  2. 回归问题

    • 如房价预测、销售额预测、风险评估等。
  3. 排序任务

    • 如搜索引擎的结果排序、推荐系统中的内容排序等。
  4. 多模态数据处理

    • 能够处理多种类型的特征(如数值型、类别型),适用于特征类型多样的数据集。

现实中著名的使用案例

  1. Yahoo! 排序算法
    Yahoo! 在其搜索引擎排序算法中使用了 GBDT,用于提高搜索结果的相关性。
  2. LinkedIn
    LinkedIn 使用 GBDT 进行推荐系统和广告点击率预测,通过优化用户体验和广告投放效果。
  3. Facebook
    Facebook 使用 GBDT 进行广告点击率预测和内容推荐,帮助提升用户参与度和广告收入。
  4. 保险公司
    许多保险公司使用 GBDT 进行风险评估和欺诈检测,通过更准确地预测风险和识别欺诈行为,提高业务效率。

5. 代码实现

5.1 python函数

from sklearn.ensemble import GradientBoostingClassifier, GradientBoostingRegressor


clf = GradientBoostingClassifier(
    """ 常用于分类 """

    # 树的数量,即迭代次数。默认值100。调整范围(50-500)。
    # 增加提高模型拟合能力,但也会增加训练时间和过拟合风险。
    # 一般与 `learning_rate` 结合调整。
    n_estimators=200,
  
    # 学习率,每棵树对最终结果的贡献。默认值0.1。调整范围(0.01-0.3)。
    # 较低的学习率需要更多的树,通常与 `n_estimators` 一起调整。
    learning_rate=0.05,
  
    # 每棵树的最大深度。默认值3。调整范围(3-10)。
    # 较大的深度可能导致过拟合,较小的深度可能导致欠拟合。一般在3到6之间选择。
    max_depth=4,
  
    # 分裂内部节点所需的最小样本数。默认值2。调整范围(2-100)。
    # 增大 `min_samples_split` 可以防止模型过拟合。
    min_samples_split=5,
  
    # 叶节点所需的最小样本数。默认值1。调整范围(1-50)。
    # 增加 `min_samples_leaf` 可以防止模型过拟合。一般在1到10之间选择。
    min_samples_leaf=3,
  
    # 每棵树拟合时抽取的样本比例。默认值1.0。调整范围(0.5-1.0)。
    # 较低的 `subsample` 值可以增加模型的随机性,防止过拟合。常见值为0.8。
    subsample=0.8,
  
    # 寻找最佳分裂时要考虑的特征数量。默认值None。
    # 调整范围('auto', 'sqrt', 'log2', 或特定数值)。回归sqrt,分类log2
    max_features='log2',
  
    # 随机种子。默认值None。调整范围任意整数。
    # 设置 `random_state` 可以保证结果的可重复性,在调参和实际应用中非常重要。
    random_state=42
)

reg = GradientBoostingRegressor(
     """ 常用于回归 """

    # 同上
    n_estimators=200, 
    # 同上
    learning_rate=0.05, 
    # 同上
    max_depth=4, 
    # 同上
    min_samples_split=5, 
    # 同上
    min_samples_leaf=3, 
    # 同上
    subsample=0.8, 
    # 同上
    max_features='sqrt',
    # 同上
    random_state=42
)
  • 经常需要调整的参数
    • n_estimators:调整范围为50到500。
    • learning_rate:调整范围为0.01到0.3。
    • max_depth:调整范围为3到10。
    • subsample:引入随机性,防止过拟合,通常设置为0.8。调整范围为0.5到1.0。
    • max_features:在寻找最佳分裂时考虑的特征数量,通常设置为'sqrt'或'log2'。调整范围为'sqrt', 'log2' 或特定数值。
    • random_state:用于保证结果可重复性,通常设置为一个固定值。

5.2 代码实现

from sklearn.ensemble import GradientBoostingClassifier
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

# generate toy dataset
X, y = make_classification(n_samples=1000, n_features=20, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# training model
clf = GradientBoostingClassifier(
    n_estimators=200,
    learning_rate=0.05,
    max_depth=4,
    min_samples_split=5,
    min_samples_leaf=3,
    subsample=0.8,
    max_features='sqrt',
    random_state=42
)
clf.fit(X_train, y_train)

# predict
y_pred = clf.predict_proba(X_test)[:, 1]
print("AUC Score:", roc_auc_score(y_test, y_pred))

到此,我们对GBDT已经有了一定的了解。原计划中,本想详细介绍XGBT,但考虑到篇幅原因,我决定将其作为下一篇文章进行介绍。