1. 强强联合的集成学习
在之前的初识提升方法和回归中的逐步向前思想与可加模型原理中,我们已经了解了:
- 决策树(Decision Tree):一种直观、易于解释的机器学习模型,它通过一系列基于特征的判断(“if-else”规则)来做出预测。
- 分类树:在叶节点上根据多数表决(众数思想)来确定类别。
- 回归树:在叶节点上根据平均值(均值思想)来做出预测。
- 树桩(Decision Stump):最简单的决策树,只包含一个根节点和两个叶节点,即只基于一个特征进行一次分裂。
- 提升方法(Boosting):一种迭代的集成学习策略,它通过串行训练多个弱学习器,并让每个后续学习器关注前一个学习器犯错的样本,从而“提升”整体性能。AdaBoost就是其经典代表,它通过调整样本权重和弱学习器权重来纠正错误。
- 前向分步算法(Forward Stagewise Additive Model):一种通用的迭代优化框架,它通过逐步添加基函数来构建一个加性模型,并在每一步优化局部损失函数。
提升树正是将上述概念巧妙结合的产物:它以决策树为基学习器(通常是浅层决策树,甚至是决策树桩),并采用前向分步算法的思想来迭代地训练这些基学习器,从而构建一个强大的集成模型。
2. 提升树算法:前向分步与残差拟合
提升树模型可以表示为决策树的加性组合: 其中 是第 棵决策树, 是这棵树的参数(例如,分裂点、叶节点值等)。
与AdaBoost通过调整样本权重来关注错误不同,标准的回归提升树(Gradient Boosting Regression Tree, GBRT 的前身)采用了一种更直接的方式来纠正错误:拟合残差(Fitting Residuals)。
2.1 核心思想:每棵树学习残差
假设我们有一个回归任务,目标是预测 。
- 第一步:我们训练第一棵回归树 来预测 。这棵树可能无法完美预测所有 值,会留下一些残差(实际值与预测值之间的差异)。
- 第二步:我们不直接训练第二棵树去预测 。相反,我们==训练第二棵回归树 去预测第一棵树留下的残差==。这样,第二棵树就专注于纠正第一棵树的错误。
- 重复:这个过程不断重复。每一棵新的树都去学习前一棵(或前几棵树的累积)模型所留下的残差。
- 累积:最终的预测是所有这些树的预测值之和。
这个过程完美地体现了前向分步算法的精神:在每一步,通过添加一个新的基学习器来优化当前模型的不足。
2.2 算法步骤详解(针对回归问题,使用平方损失)
对于回归问题,我们通常使用平方损失函数 。
算法流程:
步骤 0:初始化
- 将初始模型设为常数函数,即一个只包含截距的模型。这个常数通常是训练集 的均值,或者直接初始化为0。
步骤 1:迭代训练基学习器 对于 轮迭代:
(a) 计算当前模型的残差: 在第 轮,计算每个样本的残差 。这些残差是真实值 与当前累积模型 的预测值之间的差异。
- 解释:这些残差就是当前模型未能解释的“误差”。我们希望下一棵树能够解释这些误差。
(b) 训练新的回归树 : 以 作为新的训练数据,训练一棵回归树 。这棵树的目标是拟合这些残差,即最小化 。
- 回归树的构建:回归树通过递归地将特征空间划分为若干个不相交的区域 。在每个区域 内,预测值是该区域内所有样本目标值(在这里是残差 )的平均值。 其中 是这棵树的叶节点数量, 是第 个叶节点区域的预测值(即该区域内残差的平均值)。 选择最佳分裂点的标准是使得分裂后两区域的残差平方和最小。
(c) 更新累积模型: 将新训练的回归树 加入到当前模型中,得到更新后的模型 。
- 解释:这正是前向分步算法的体现。新的树直接添加到旧模型上,其预测值就是对旧模型误差的修正。
步骤 2:得到最终模型 经过 轮迭代后,最终的提升树模型为:
3. 提升树数值计算示例(回归问题)
训练数据集:10个样本,特征 ,标签 。
| 序号 | ||
|---|---|---|
| 1 | 1 | 5.56 |
| 2 | 2 | 5.70 |
| 3 | 3 | 5.91 |
| 4 | 4 | 6.40 |
| 5 | 5 | 6.80 |
| 6 | 6 | 7.05 |
| 7 | 7 | 8.90 |
| 8 | 8 | 8.70 |
| 9 | 9 | 9.00 |
| 10 | 10 | 9.05 |
目标:演示前三轮迭代的详细计算。在这里,我们假设基学习器是决策树桩(即只进行一次分裂)。
3.1 第一轮迭代 ()
步骤 0:初始化
步骤 1a:计算残差 由于 ,所以第一轮的残差就是原始的 :
步骤 1b:训练回归树 来拟合 () 我们要找到一个最佳分裂点 ,将数据分为两部分 和 ,使得分裂后两区域的残差平方和最小。 可能的候选分裂点 是相邻样本 值的中间点。 值排序:1, 2, 3, 4, 5, 6, 7, 8, 9, 10 可能的 值:1.5, 2.5, 3.5, 4.5, 5.5, 6.5, 7.5, 8.5, 9.5
对于每个 ,我们计算其左区域和右区域的均值,并计算总的平方误差。 例如,对于 :
- 区域 ,对应的 值是 。 该区域的均值
- 区域 ,对应的 值是 。 该区域的均值
计算 的总平方误差: 这个误差值就是 表格中的1.9300。
图片中 表格的计算结果(总平方误差):
| 值 | (总平方误差) |
|---|---|
| 1.5 | 15.7231 |
| 2.5 | 12.0834 |
| 3.5 | 8.3656 |
| 4.5 | 5.7755 |
| 5.5 | 3.9113 |
| 6.5 | 1.9300 |
| 7.5 | 8.0098 |
| 8.5 | 11.7354 |
| 9.5 | 15.7386 |
通过比较,我们发现当分裂点 时,总平方误差最小(1.9300)。 因此,第一棵回归树 为:
步骤 1c:更新模型
3.2 第二轮迭代 ()
步骤 2a:计算残差
| 序号 | ||||
|---|---|---|---|---|
| 1 | 1 | 5.56 | 6.24 | -0.68 |
| 2 | 2 | 5.70 | 6.24 | -0.54 |
| 3 | 3 | 5.91 | 6.24 | -0.33 |
| 4 | 4 | 6.40 | 6.24 | 0.16 |
| 5 | 5 | 6.80 | 6.24 | 0.56 |
| 6 | 6 | 7.05 | 6.24 | 0.81 |
| 7 | 7 | 8.90 | 8.91 | -0.01 |
| 8 | 8 | 8.70 | 8.91 | -0.21 |
| 9 | 9 | 9.00 | 8.91 | 0.09 |
| 10 | 10 | 9.05 | 8.91 | 0.14 |
步骤 2b:训练回归树 来拟合 现在,我们使用 作为训练数据来寻找最佳分裂点 。 第二棵树选择的最佳分裂点 。
- 区域 , 对应样本 。 对应的残差 是 。 该区域的残差均值
- 区域 , 对应样本 。 对应的残差 是 。 该区域的残差均值
因此,第二棵回归树 为:
步骤 2c:更新模型 让我们看看 的预测规则:
- Case 1: (即 且 )
- Case 2: (即 且 )
- Case 3: (即 )
所以,更新后的模型 为:
3.3 第三轮迭代 ()
步骤 3a:计算残差
| 序号 | ||||
|---|---|---|---|---|
| 1 | 1 | 5.56 | 5.72 | -0.16 |
| 2 | 2 | 5.70 | 5.72 | -0.02 |
| 3 | 3 | 5.91 | 5.72 | 0.19 |
| 4 | 4 | 6.40 | 6.46 | -0.06 |
| 5 | 5 | 6.80 | 6.46 | 0.34 |
| 6 | 6 | 7.05 | 6.46 | 0.59 |
| 7 | 7 | 8.90 | 9.13 | -0.23 |
| 8 | 8 | 8.70 | 9.13 | -0.43 |
| 9 | 9 | 9.00 | 9.13 | -0.13 |
| 10 | 10 | 9.05 | 9.13 | -0.08 |
步骤 3b:训练回归树 来拟合 使用 作为训练数据。
- 区域 , 对应样本 。 对应的残差 是 。 该区域的残差均值
- 区域 , 对应样本 。 对应的残差 是 。 该区域的残差均值
因此,第三棵回归树 按照我们的原理推导为:
步骤 3c:更新模型 让我们看看 的预测规则:
- Case 1: (即 且 )
- Case 2: (即 且 )
- Case 3: (即 )
- Case 4: (即 )
所以,更新后的模型 为:
通过三轮迭代,我们构建了一个分段常数函数 来拟合原始数据。每增加一棵树,模型对数据的拟合能力就越强,残差也越来越小。
4. 从提升树到梯度提升
4.1 从拟合残差到泛化损失
在上一节,我们学习了回归提升树(Boosting Tree for Regression),其核心思想是:每一棵新的回归树都去拟合前一棵树(或前面所有树的累积)所留下的残差。 这种方法对于平方损失函数 来说非常有效,因为平方损失的梯度(即残差)就是 。所以,拟合残差等价于拟合损失函数的负梯度。
然而,平方损失并非适用于所有任务。例如:
- 分类问题:我们可能希望使用交叉熵损失(Cross-Entropy Loss)。
- 排序问题:我们可能关心的是排序的准确性,而不是预测值的精确度。
- 鲁棒性问题:平方损失对异常值敏感,我们可能希望使用绝对值损失(Absolute Error Loss)或其他更鲁棒的损失函数。
对于这些不同的损失函数,简单地拟合“残差”不再适用。那么,有没有一种更通用的提升方法,可以适用于任何可微分的损失函数呢?答案就是梯度提升(Gradient Boosting)。
4.2 为什么需要梯度提升?
==梯度提升的核心思想是:将梯度下降算法从参数空间推广到函数空间。==
如何理解?
- 参数空间的梯度下降:在传统的优化中,我们通过计算损失函数关于模型参数的梯度,然后沿着梯度的负方向更新参数,以使损失最小化。例如,在线性回归中,我们更新 。
- 函数空间的梯度下降:在梯度提升中,我们不是更新参数,而是更新整个模型(函数)本身。我们寻找一个“方向”,使得沿着这个方向更新模型,能够最大程度地降低损失。这个“方向”就是损失函数在当前模型处的负梯度。
在每一步迭代中,梯度提升不再拟合简单的残差,而是拟合当前模型在损失函数上的负梯度。这些负梯度被称为伪残差(Pseudo-Residuals)。
4.3 梯度下降与“梯度上升”的澄清
这里需要对“梯度上升”一词进行澄清。在机器学习中,我们的目标通常是最小化损失函数。因此,我们总是沿着梯度的负方向进行优化,这被称为梯度下降(Gradient Descent)。 如果有人提到“梯度上升”,通常是在指最大化某个目标函数(如效用函数、奖励函数、似然函数)。例如,在某些强化学习算法中,目标是最大化累积奖励,此时会沿着梯度正方向更新。 但在梯度提升的语境下,我们是在最小化损失,所以我们进行的是梯度下降。我们计算的“伪残差”正是损失函数的负梯度,所以训练基学习器去拟合这些负梯度,就是在进行函数空间的梯度下降。
4.4 梯度提升算法(通用形式)
梯度提升算法是一种通用的加性模型训练方法,它使用任意可微分的损失函数,并以任意类型的基学习器(通常是决策树)作为组成部分。
输入:
- 训练数据集
- 损失函数 ,要求可微。
- 迭代次数 。
- 基学习器类型 (例如,回归树)。
- 学习率 (或 )。
算法步骤:
步骤 0:初始化
- 初始化一个常数模型 ,使其最小化损失函数。
- 解释:这是最简单的模型,一个常数预测。对于不同的损失函数,这个 的计算方式不同。
- 平方损失: 是 的均值。
- 绝对值损失: 是 的中位数。
- 指数损失: 稍微复杂,通常为 。
- 解释:这是最简单的模型,一个常数预测。对于不同的损失函数,这个 的计算方式不同。
步骤 1:迭代训练基学习器 对于 轮迭代:
(a) 计算伪残差(负梯度): 对于每个样本 ,计算损失函数在当前模型 处的负梯度。这被称为第 轮的伪残差 。
- 解释:负梯度指示了损失函数下降最快的方向。我们希望新的基学习器能够沿着这个方向“推”动模型。
- 举例(平方损失):如果 ,则 。所以负梯度是 。这与我们之前提升树的残差定义完全一致!
- 举例(对数损失/交叉熵,二分类):如果 ,则负梯度为 。
(b) 训练新的基学习器 : 以 作为新的训练数据(即,将伪残差作为目标值),训练一个基学习器 。这个基学习器被训练来拟合伪残差。
- 解释:这里基学习器训练的损失仍然是平方损失,目的是让 尽可能地逼近负梯度。
(c) 确定基学习器的步长(Step Size)或权重 : 一旦训练好 ,我们需要确定它对整体模型的贡献程度。我们找到一个最佳的步长 来最小化整体损失函数。
- 解释:这个 确保了新添加的基学习器 以最佳的“强度”加入到现有模型中,进一步减小损失。
(d) 更新累积模型: 将确定了步长的基学习器加入到当前模型中。通常还会引入一个学习率(Learning Rate),以防止过拟合,并提高模型的泛化能力。
- 解释:学习率 (也常写为 或 )是一个超参数,它控制了每棵树对最终模型的影响力。小的学习率意味着需要更多的树来达到相同效果,但通常能得到更好的泛化性能。
步骤 2:得到最终模型 经过 轮迭代后,最终的梯度提升模型为: 对于分类问题,最终的预测需要通过一个激活函数(如 sigmoid 或 softmax)将 转换为概率,然后进行分类。
4.5 梯度提升回归树 (GBRT) / GBDT:通用算法的树形实现
当我们将决策树(通常是回归树,即便用于分类任务) 作为梯度提升算法中的基学习器 时,这个算法就成为了梯度提升回归树(Gradient Boosting Regression Tree, GBRT) ,通常简称为 GBDT (Gradient Boosting Decision Tree)。
- 为什么选择决策树作为基学习器?
- 非线性能力:决策树可以捕捉特征之间的非线性关系,因为它们通过分段常数函数来近似目标函数。
- 特征交互:决策树能够自动发现并建模特征之间的交互作用(通过多层分裂)。这是线性模型难以做到的。
- 处理混合数据类型:决策树能自然地处理数值型和类别型特征。
- 鲁棒性:决策树对异常值和尺度不敏感。
- GBDT 的优势:
- 高精度:通常能达到非常高的预测精度。
- 灵活性:可以配合各种损失函数和基学习器。
- 鲁棒性:对特征的缩放和异常值不敏感。
- 可解释性(一定程度上):虽然整个GBDT模型像一个黑箱,但单个树桩的可解释性较好,且可以通过特征重要性分析来理解模型。
5. GBDT 在推荐系统中的应用
5.1 推荐系统概述:为什么它如此重要?
推荐系统(Recommendation Systems, RS)是当今数字生活中无处不在的技术,从电商(亚马逊、淘宝)到流媒体(Netflix、YouTube),再到社交媒体(Facebook、TikTok),它们通过分析用户的历史行为和偏好,预测用户可能感兴趣的物品,从而提升用户体验、增加平台活跃度和商业收入。
推荐系统的核心挑战:
- 海量数据:用户、物品、行为数据规模巨大。
- 稀疏性:用户只与极少数物品发生过交互,数据矩阵高度稀疏。
- 多样性:用户兴趣多变,物品属性多样。
- 时效性:用户兴趣可能随时间变化,物品流行度也会变化。
- 冷启动:新用户或新物品缺乏历史数据,难以进行有效推荐。
- 可解释性:用户希望知道为什么会推荐某个物品。
5.2 为什么 GBDT 适合推荐系统?
GBDT 在推荐系统中扮演着越来越重要的角色,尤其是在传统的协同过滤(Collaborative Filtering) 和矩阵分解(Matrix Factorization) 模型之后,作为特征工程和排序阶段的强大工具。
GBDT 适合推荐系统的原因主要包括:
- 强大的非线性建模能力:推荐系统中的用户行为、物品特征和上下文信息之间存在复杂的非线性关系。GBDT 能够通过其决策树基学习器天然地捕捉这些关系,而无需手动进行复杂的非线性特征转换。
- 自动捕获特征交互:用户特征(年龄、性别)、物品特征(类别、品牌)和上下文特征(时间、地点)之间的交互对推荐结果至关重要(例如,年轻男性在晚上更可能看动作电影)。GBDT 的决策树结构能够自动发现和建模这些高阶、复杂的特征交互,无需人工特征组合。
- 处理混合数据类型:推荐系统中常常包含数值型(如用户年龄、商品价格)和类别型(如性别、商品类别)特征。决策树能自然处理这些混合数据类型,避免了复杂的预处理。
- 对缺失值和异常值不敏感:决策树对缺失值和异常值具有一定的鲁棒性,减少了对数据清洗的严格要求。
- 优秀的排序能力:GBDT 非常擅长预测CTR(点击率)、CVR(转化率)等连续值或概率,这使得它成为在线广告和推荐排序场景中的首选模型。通过最小化对数损失或自定义损失,GBDT 可以直接优化排序效果。
- 特征重要性:虽然 GBDT 本身是集成模型,但可以通过计算特征在所有树中分裂节点的平均增益来评估特征重要性,这有助于理解哪些特征对推荐结果贡献最大。
- 可与传统方法结合:GBDT 可以作为特征工程的工具,与传统的协同过滤或矩阵分解方法结合,共同提升推荐效果(例如,将 GBDT 的叶节点作为新的特征输入到其他模型)。
5.3 GBDT 在推荐系统中的典型应用场景
GBDT 在推荐系统中主要应用于以下几个阶段:
- CTR/CVR 预估(点击率/转化率预测):这是最常见的应用。推荐系统通常会生成大量的候选物品,然后使用 GBDT 模型来预测每个物品被用户点击或购买的概率,并根据这些概率进行排序。
- 输入特征:
- 用户特征:年龄、性别、地域、消费能力、历史点击/购买品类偏好等。
- 物品特征:类别、品牌、价格、受欢迎程度、标签等。
- 上下文特征:时间(工作日/周末、白天/夜晚)、地点、设备(手机/PC)等。
- 交叉特征:用户-物品交互特征(如用户对某个品牌的偏好程度)、用户-上下文交互特征等。
- 目标变量:用户是否点击(0/1)、是否购买(0/1)。
- 损失函数:通常使用二分类的对数损失(LogLoss)来优化。
- 输入特征:
- 特征工程(Feature Engineering):
GBDT 训练完成后,其每一棵树的叶节点可以被视为一种非线性特征组合。将一个样本最终落入的叶节点 ID 编码为新的特征(One-Hot Encoding),可以生成高阶的、非线性的、类别型特征。这些新特征可以作为输入,提供给其他模型(如逻辑回归、Factorization Machine 或深度学习模型),从而提升它们的性能。这种“GBDT + LR”或“GBDT + FM”的组合在业界非常流行。
- 优势:GBDT 自动发现复杂特征交互,省去了大量人工特征工程。
- 多目标优化: 实际推荐系统通常有多个目标(如点击、购买、停留时长、分享等)。GBDT 可以通过构建多个 GBDT 模型来分别优化每个目标,或者通过多任务学习(Multi-Task Learning)的方式来联合优化。
- 冷启动问题(Cold Start)的辅助: 虽然 GBDT 本身也依赖数据,但相比于纯协同过滤,它可以通过物品的属性特征(即使是新物品)和用户的历史属性特征(即使是新用户)来做预测,一定程度上缓解冷启动问题。
GBDT 在推荐系统中的工作流示例:
假设我们要预测用户是否会点击某个商品:
- 数据收集:收集用户、商品、上下文信息。
- 特征提取:将原始数据转换为 GBDT 可以接受的特征向量。
- 用户ID → 用户历史行为统计特征(平均消费金额、偏好类别占比)
- 商品ID → 商品属性特征(类别、品牌、价格)
- 时间 → 是否周末、小时
- 模型训练:
- 初始化:
- 迭代 :
- 计算伪残差 :对于二分类对数损失,伪残差是 ,其中 是当前模型预测的概率。
- 训练回归树 :用 训练一棵新的回归树。
- 更新模型: (这里简化了 的计算,直接将学习率 乘以树的输出)。
- 模型预测:对于新的用户-商品对 ,计算 ,然后通过 得到点击概率。
- 排序:根据预测的点击概率对商品进行排序,展示给用户。
5.4 GBDT 在推荐系统中的挑战与考虑
尽管 GBDT 强大,但在推荐系统中应用时也面临一些挑战:
- 可解释性相对较低:虽然比深度学习模型好,但作为一个大型的树集成模型,难以直观理解单个特征的精确影响路径。
- 大规模性挑战:对于拥有数十亿用户和商品的超大规模推荐系统,训练 GBDT 可能非常耗时和资源密集。这促使了 XGBoost、LightGBM 等高效 GBDT 实现的发展。
- 冷启动(模型自身):GBDT 依赖于丰富的特征,如果新用户或新物品缺乏足够的特征信息,GBDT 也可能表现不佳。
- 时序性处理:标准 GBDT 对时序性不敏感。为了处理用户兴趣漂移和物品流行度变化,需要结合时序特征、使用滑动时间窗口训练模型,或结合序列模型。