梯度提升算法:完整指南

了解如何使用梯度增强算法(一种强大的机器学习技术)来改进您的预测模型。本教程涵盖了梯度提升的理论和实践。

您将在本教程中学到什么?

这篇文章最重要的收获是,您可以非常牢固地掌握梯度提升的内部工作原理,而不会遇到太多数学难题。毕竟,梯度提升是用于实践的,而不是用于数学分析的。

一般而言什么是梯度提升?

Boosting 是机器学习中一种强大的集成技术。与独立从数据中学习的传统模型不同,Boosting 结合了多个弱学习器的预测来创建一个更准确的强学习器。

我刚刚写了一堆新术语,所以让我从弱学习者开始解释每个术语。

A 弱学习器是一种比随机猜测模型稍好的机器学习模型。例如,假设我们将蘑菇分为可食用和不可食用。如果随机猜测模型的准确率为 40%,那么弱学习器的准确率将略高于此:50-60%。

Boosting 将数十或数百个弱学习器组合起来,构建一个强学习器,在同一问题上有可能达到 95% 以上的准确率。

最流行的弱学习器是决策树,选择它是因为它们能够处理几乎任何数据集。如果您不熟悉决策树,请查看此 DataCamp 决策树分类教程

梯度提升的实际应用

梯度提升已成为机器学习的主导力量,其应用现已跨越各个行业,从预测客户流失到检测小行星。以下是其在 Kaggle 和现实世界用例中的成功故事:

称霸 Kaggle 比赛:

  • Otto Group 产品分类挑战赛:所有前 10 名位置均使用 XGBoost 实现梯度提升。
  • Santander 客户交易预测:基于 XGBoost 的解决方案再次稳坐预测客户行为和金融交易的榜首。
  • Netflix 电影推荐挑战:梯度提升在为 Netflix 等数十亿美元的公司构建推荐系统方面发挥了至关重要的作用。

改变商业和工业:

  • 零售和电子商务:个性化推荐、库存管理、欺诈检测
  • 金融和保险:信用风险评估、客户流失预测、算法交易
  • 医疗保健和医学:疾病诊断、药物发现、个性化医疗
  • 搜索和在线广告:搜索排名、广告定位、点击率预测

那么,让我们最终一睹这个传奇算法的幕后花絮吧!

梯度增强算法:分步指南

输入

梯度增强算法适用于具有一组特征 (X) 和目标 (y) 的表格数据。与其他机器学习算法一样,其目的是从训练数据中学习足够的知识,以便很好地推广到未见过的数据点。

为了理解梯度提升的基本过程,我们将使用一个包含四行的简单销售数据集。使用三个特征——客户年龄、购买类别和购买重量,我们想要预测购买金额:

包含四行、三个特征、一个目标的示例表

梯度提升中的损失函数

在机器学习中,损失函数是一个关键组件,可让我们量​​化模型预测与实际值之间的差异。本质上,它衡量模型的表现。

以下是其作用的详细说明:

  • 计算误差:获取模型的预测输出并将其与基本事实(实际观测值)进行比较。它的比较方式(即计算差异)因函数而异。
  • 指导模型训练:模型的目标是最小化损失函数。在整个训练过程中,模型不断更新其内部架构和配置,以使损失尽可能小。
  • 评估指标:通过比较训练、验证和测试数据集的损失,您可以评估模型的泛化能力和避免过度拟合的能力。

两个最常见的损失函数是:

  • 均方误差 (MSE):这种流行的回归损失函数测量预测值与实际值之间的平方差之和。梯度提升经常使用它的这种变体:
用于梯度提升的修改后的均方误差损失函数。

平方值乘以二分之一的原因与微分有关。当我们对该损失函数求导时,由于幂律,二分之一与平方相抵消。因此,最终结果就是-(Observed - Predicted),使数学变得更容易并且计算成本更低。

  • 交叉熵:该函数衡量两个概率分布之间的差异。因此,它通常用于目标具有离散类别的分类任务。

由于我们正在进行回归,因此我们将使用 MSE。

第 1 步:做出初步预测

梯度提升是一种逐渐提高准确性的算法。为了开始这个过程,我们需要一个初步的猜测或预测。初始猜测始终是目标的平均值。换句话说,对于第一轮,我们的模型预测所有购买都是相同的 — 156 美元:

计算回归目标的平均值。结果是156

选择平均值的原因与我们选择的损失函数及其导数有关。每一步,我们都在寻找一个值来找到损失函数的最小值。换句话说,我们正在寻找一个使损失函数的导数(梯度)为0的值。

当我们对每个观测值相对于预测值求损失函数的导数并将它们相加时,我们最终得到目标的平均值。

因此,我们最初的预测是平均值 — 156 美元。当我们继续时,请将其牢记在心。

步骤 2:计算伪残差

下一步是找出每个观测值与我们的初始预测之间的差异:156 - Observed。为了便于说明,我们将把这些差异放在一个新列中:

相同的数据集,但有一个额外的残差列

请记住,在线性回归中,观测值与预测值之间的差异称为残差。为了区分线性回归和梯度提升,我们将它们称为伪残差(这样命名还有其他原因,但我们不会详细讨论)它们在本文中)。

第三步:构建弱学习器

接下来,我们将构建一个决策树(弱学习器),使用我们拥有的三个特征(年龄、类别、购买重量)来预测残差。对于这个问题,我们将决策树限制为只有四个叶子(终端节点),但在实践中,人们通常选择 8 到 32 之间的叶子。

顶部有决策树的相同数据集。该树已经适合数据集。这是一个弱学习者

树适合数据后,我们对数据中的每一行进行预测。以下是第一个操作的方法:

将第一行数据放入决策树并得到预测 123.45

下图中的一个小错误:应该写的是“预计购买金额”,而不是“预计重量”

第一行有以下特征:电子产品类别(根节点左侧)和30岁以下的客户年龄(子节点左侧)。这会将 -32.55 放入叶节点。为了做出最终的预测,我们在第一个预测中添加 -32.55,这与观测值 完全相同 -  123.45 美元!

我们刚刚做出了完美的预测,那么为什么还要费心建造其他树呢?好吧,现在我们对训练数据严重过度拟合。我们希望模型能够泛化。因此,为了缓解这个问题,梯度提升有一个称为学习率的参数。

梯度提升中的学习率只是一个介于 0 和 1 之间的乘数,用于缩放每个弱学习器的预测(有关学习率的详细信息,请参阅下面的部分)。当我们将任意学习率 0.1 添加到混合中时,我们的预测变为 152.75,而不是完美的 123.45。

使用学习率重新计算预测购买添加了它。

我们也对第二行进行预测:

作为弱学习者的第二个决策树。

我们通过树运行该行并得到 146.08 作为预测。我们对所有行继续以这种方式进行,直到我们对四行有四个预测:152.75、146.08、174.945、150.2。现在让我们将它们添加为新列:

具有伪残差和新预测的新列的同一数据集

接下来,我们通过从购买金额中减去新的预测来找到新的伪残差。让我们将它们作为新列添加到表中并删除最后两列:

相同的数据集,具有新的伪残差的额外列

正如您所看到的,我们的新伪残差较小,这意味着我们的损失正在下降。

第 4 步:迭代

在接下来的步骤中,我们迭代第 3 步,即构建更多弱学习器。唯一要记住的是,我们必须不断地将每棵树的残差添加到初始预测中以生成下一棵树。

例如,如果我们构建 10 棵树,每棵树的残差表示为 r_i (1 <= i <= 10),则下一个预测将变为 p_10 = 156 + eta * (r_1 + r_2 + ... + r_10) 其中p_10表示第十轮预测。

在实践中,专业人士通常从 100 棵树开始,而不仅仅是 10 棵。在这种情况下,算法据说要训练 100 轮boosting rounds.

如果您不知道解决特定问题所需的树的确切数量,您可以使用一种称为早期停止的简单技术。

早期停止中,我们选择大量的树,例如 1000 或 10000 棵。然后,而不是等待算法完成建造所有这些树后,我们会监控损失。如果在一定数量的 boosting 轮次(例如 50 轮)后损失没有改善,我们会提前停止训练,从而节省时间和计算资源。

配置梯度提升模型

在机器学习中,选择模型的设置被称为“超参数调整”。这些设置被称为“超参数”。是机器学习工程师必须自己选择的选项。与其他参数不同,模型无法仅通过数据训练来学习超参数的最佳值。

梯度增强模型有许多超参数,我将在下面概述其中一些。

客观的

该参数设置算法的方向和损失函数。如果目标是回归,则选择 MSE 作为损失函数,而对于分类,则选择交叉熵。像 XGBoost 这样的 Python 库为其他类型的任务提供了其他目标,例如使用相应的损失函数进行排名。

学习率

梯度提升最重要的超参数可能是学习率。它通过调整收缩因子来控制每个弱学习器的贡献。较小的值(接近 0)会减少每个弱学习者在整体中的发言权。这需要建造更多的树,从而需要更多的时间来完成训练。但是,最终的强学习器确实会很强大并且不会受到过度拟合的影响。

树木数量

此参数也称为提升轮数或n_es timators,控制要构建的树的数量。您构建的树越多,整体就会变得越强大、性能越好。随着更多的树允许模型捕获数据中的更多模式,它也变得更加复杂。然而,更多的树会显着提高过度拟合的可能性。为了缓解这种情况,请结合使用提前停止和低学习率。

最大深度

该参数控制每个弱学习器(决策树)的级别数。最大深度为 3 意味着树中有三个级别(计算叶级别)。树越深,模型就越复杂,计算成本也越高。选择接近 3 的值以防止过度拟合。最大深度应为 10。

每片叶子的最小样本数

该参数控制决策树中分支的分割方式。为终止节点(叶)中的样本数量设置较低的值会使整个算法对噪声敏感。较大的最小样本数使树更难以基于太少的数据点创建分裂,从而有助于防止过度拟合。

二次采样率

该参数控制用于训练每棵树的数据比例。在上面的示例中,我们使用了 100% 的行,因为数据集中只有四行。但是,现实世界的数据集通常包含更多数据并且需要采样。因此,如果将子采样率设置为低于 1 的值(例如 0.7),则每个弱学习器都会在随机采样的 70% 的行上进行训练。较小的子采样率可以导致更快的训练,但也可能导致过度拟合。

特征采样率

此参数与二次采样完全相同,但它对行进行采样。对于具有数百个特征的数据集,建议选择0.5到1之间的特征采样率,以降低过度拟合的机会。

梯度提升是我们对于表格监督学习任务最有能力的模型。因此,大多数时候,您不必担心它不足以完成任务。当你使用梯度提升时,你的时间几乎总是花在如何对其进行正则化上——控制它的力量,这样它就不会吞噬你的数据集,并且在涉及到看不见的数据时变得毫无用处。

我介绍的超参数都可以帮助您完成此任务,并且它们包含在 Python 中梯度提升的每​​个实现中。好好利用它们。

用 Python 实现的梯度提升

正如我之前提到的,梯度提升通过 Python 库已经很成熟。以下是主要的四种:

  • XGBoost:极限梯度提升
  • LightGBM:光梯度增强机
  • CatBoost:分类提升
  • Scikit-learn:有两个用于回归和分类的估计器

前三个库彼此相似:

  • 主导性能
  • GPU支持
  • 丰富的超参数集(配置友好)
  • 非常高的社区支持
  • 工业上广泛使用

这三个库的一个流行替代品是 Scikit-learn,它的缺点是仅适用于 CPU。由于梯度提升是一种计算量大的算法,因此对于大型数据集(我们谈论的是数十万行)来说,在 CPU 上运行它可能是不可行的。

然而,我们必须记住,Scikit-learn 本身比这三个库加在一起更受欢迎。除了用于分类和回归的两个梯度增强估计器之外,Scikit-learn 还为无数监督和无监督学习任务提供了数十种其他模型。

此外,使用 Scikit-learn 构建的梯度提升模型可以集成到其丰富的生态系统中,例如管道、交叉验证估计器、数据处理器等。

以下是有关如何使用 GradientBoostingClassifier 进行分类的分步指南。我们将根据钻石的价格和其他物理测量来预测钻石的切工质量。该数据集内置于 Seaborn 库中。

专业提示:使用 DataCamp 代码片段编辑器的“解释代码”按钮来获取所发生情况的详细逐行解释。

1. 导入库

import pandas as pd
import seaborn as sns
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.metrics import classification_report
from sklearn.model_selection import cross_val_score, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, StandardScaler

2. 加载数据

# Load the diamonds dataset from Seaborn
diamonds = sns.load_dataset("diamonds")

# Split data into features and target
X = diamonds.drop("cut", axis=1)
y = diamonds["cut"]

3. 分割数据

# Split data into train and test sets
X_train, X_test, y_train, y_test = train_test_split(
   X, y, test_size=0.2, random_state=42
)

4. 定义分类和数字特征

# Define categorical and numerical features
categorical_features = X.select_dtypes(
   include=["object"]
).columns.tolist()

numerical_features = X.select_dtypes(
   include=["float64", "int64"]
).columns.tolist()

5. 定义分类和数值特征的预处理步骤

preprocessor = ColumnTransformer(
   transformers=[
       ("cat", OneHotEncoder(), categorical_features),
       ("num", StandardScaler(), numerical_features),
   ]
)

6. 创建梯度提升分类器管道

pipeline = Pipeline(
   [
       ("preprocessor", preprocessor),
       ("classifier", GradientBoostingClassifier(random_state=42)),
   ]
)

7. 简历和培训

# Perform 5-fold cross-validation
cv_scores = cross_val_score(pipeline, X_train, y_train, cv=5)

# Fit the model on the training data
pipeline.fit(X_train, y_train)

# Predict on the test set
y_pred = pipeline.predict(X_test)

# Generate classification report
report = classification_report(y_test, y_pred

8. 报告最终结果

print(f"Mean Cross-Validation Accuracy: {cv_scores.mean():.4f}")
print("\nClassification Report:")
print(report)

Mean Cross-Validation Accuracy: 0.7621

Classification Report:
             precision    recall  f1-score   support

       Fair       0.90      0.91      0.91       335
       Good       0.81      0.63      0.71      1004
      Ideal       0.82      0.91      0.86      4292
    Premium       0.70      0.86      0.77      2775
  Very Good       0.66      0.41      0.51      2382

   accuracy                           0.76     10788
  macro avg       0.78      0.74      0.75     10788
weighted avg       0.75      0.76      0.75     10788

加权准确度为 75%,这对于默认参数的基线模型来说还不错。因此,作为一项挑战,我让您调整 GradientBoostingClassifier 的超参数以实现超过 95% 的性能。对的,这是可能的! (提示:仔细阅读最后一节并查看分类器的 Scikit-learn 文档 ).

#algorithm

梯度提升算法:完整指南
1.60 GEEK