Day 10:集成学习进阶(Boosting: AdaBoost, GBDT)

Day 10:集成学习进阶(Boosting: AdaBoost, GBDT)

📋 目录

  1. Boosting 基础原理
  2. AdaBoost 算法详解
  3. 梯度提升机 (GBDT) 原理
  4. AdaBoost vs GBDT vs 随机森林
  5. GBDT 核心超参数
  6. 损失函数与优化

第一部分:Boosting 基础原理(1.5小时理论)

1.1 什么是 Boosting?

定义 :Boosting 是一种将多个弱学习器串行 组合成强学习器的集成方法,每个新模型都关注前一个模型犯错的样本。

核心思想 :三个臭皮匠,通过递进式学习变成诸葛亮。

与 Bagging 的核心区别

特性 Bagging (随机森林) Boosting (AdaBoost/GBDT)
训练方式 并行训练 串行训练
样本权重 均匀采样 动态调整权重
模型权重 平等投票 根据性能加权
目标 降低方差 降低偏差
过拟合风险 较低 较高(需调参)

1.2 Boosting 的工作流程

text 复制代码
初始化样本权重 (均匀)
    ↓
训练弱学习器 h₁
    ↓
计算 h₁ 的误差,更新样本权重(错误样本权重↑)
    ↓
训练弱学习器 h₂(关注上一轮错误样本)
    ↓
计算 h₂ 的误差,更新样本权重
    ↓
... 重复 T 次 ...
    ↓
加权组合所有弱学习器得到最终强学习器

1.3 Boosting 的数学原理

加法模型
F(x)=∑t=1Tαtht(x) F(x)= \sum_{t=1}^T \alpha_th_t(x) F(x)=t=1∑Tαtht(x)

其中:

  • hth_tht:第 ttt 个弱学习器
  • αt\alpha_tαt:第 ttt 个学习器的权重(表现越好,权重越大)

前向分步算法
Ft(x)=Ft−1(x)+αtht(x) F_t(x)=F_{t−1}(x) + \alpha_th_t(x) Ft(x)=Ft−1(x)+αtht(x)

每一步最小化损失函数:
(αt,ht)=arg⁡minα,h∑i=1nL(yi,Ft−1(xi)+αh(xi)) (\alpha_t,h_t) = \text{arg⁡min}{\alpha,h} \sum{i=1}^n L(y_i, F_{t−1}(x_i) + \alpha h(x_i)) (αt,ht)=arg⁡minα,hi=1∑nL(yi,Ft−1(xi)+αh(xi))

1.4 Boosting 的优缺点

优点

  • 高精度:通常优于 Bagging
  • 灵活:可使用多种损失函数
  • 特征重要性:自动评估

缺点

  • 对异常值敏感
  • 训练较慢(串行)
  • 容易过拟合(需仔细调参)

第二部分:AdaBoost 算法详解

2.1 AdaBoost 原理

AdaBoost (Adaptive Boosting,自适应增强) :第一个实用的 Boosting 算法,通过调整样本权重基学习器权重实现。

算法步骤

  1. 初始化样本权重 (假设共有 nnn 个样本):
    w1(i)=1n,i=1,2,...,n w_1^{(i)} = \frac{1}{n}, \quad i = 1, 2, \dots, n w1(i)=n1,i=1,2,...,n

  2. 迭代训练弱分类器(进行 T 轮迭代,对于 t = 1 到 T):

    • 训练弱学习器 hth_tht(使用权重 wtw_twt)

    • 计算加权误差率:
      ϵt=∑i=1nwt(i)⋅I(ht(xi)≠yi)∑i=1nwt(i) \epsilon_t = \frac{\sum_{i=1}^n w_t^{(i)} \cdot \mathbb{I}(h_t(x_i) \neq y_i)}{\sum_{i=1}^n w_t^{(i)}} ϵt=∑i=1nwt(i)∑i=1nwt(i)⋅I(ht(xi)=yi)

    • 计算学习器权重:
      αt=12ln⁡(1−ϵtϵt) \alpha_t = \frac{1}{2} \ln \left( \frac{1 - \epsilon_t}{\epsilon_t} \right) αt=21ln(ϵt1−ϵt)
      ϵt\epsilon_tϵt 越小,αt\alpha_tαt 越大。

    • 更新样本权重:
      wt+1(i)=wt(i)⋅exp⁡(−αtyiht(xi)) w_{t+1}^{(i)} = w_t^{(i)} \cdot \exp \left( -\alpha_t y_i h_t(x_i) \right) wt+1(i)=wt(i)⋅exp(−αtyiht(xi))

      这里二分类标签为 1 或 -1,所以 实际值 yiy_iyi 和预测值 ht(xi)h_t(x_i)ht(xi) 取值为 1 或 -1。

    • 归一化权重

  3. 输出最终模型
    H(x)=sign(∑t=1Tαtht(x)) H(x) = \text{sign} \left( \sum_{t=1}^T \alpha_t h_t(x) \right) H(x)=sign(t=1∑Tαtht(x))

2.2 AdaBoost 的权重更新

直观理解

  • 分类错误的样本:权重增加(×eαt\times e^{\alpha_t}×eαt)
  • 分类正确的样本:权重减少(×e−αt\times e^{-\alpha_t}×e−αt)

示例

python 复制代码
# 假设 α = 0.5
# 错误样本新权重 = 旧权重 × 1.648
# 正确样本新权重 = 旧权重 × 0.607

2.3 AdaBoost 的基学习器

常用基学习器

  • 决策树桩(stump):只有1个分裂节点的决策树(默认)
  • 浅层决策树(max_depth=1-3)

为什么用弱学习器

  • 防止过拟合
  • 体现 Boosting 的"递进"思想
  • 计算效率高

2.4 AdaBoost 的损失函数

指数损失函数
L(y,F(x))=exp⁡(−yF(x)) L(y,F(x))=exp⁡(−yF(x)) L(y,F(x))=exp⁡(−yF(x))
特点

  • 对异常值敏感
  • 分类边界会偏向困难样本

第三部分:梯度提升机 (GBDT) 原理

3.1 从 AdaBoost 到 GBDT

AdaBoost 的限制

  • 仅支持指数损失(二分类)
  • 难以扩展到回归和多分类

GBDT 的突破

  • 任何可微损失函数
  • 统一框架:回归、分类、排序

3.2 GBDT 核心思想

关键洞察 :将 Boosting 视为函数空间上的梯度下降

算法流程

  1. 初始化:
    F0(x)=arg⁡min⁡γ∑i=1nL(yi,γ) F_0(x) = \arg\min_{\gamma} \sum_{i=1}^n L(y_i, \gamma) F0(x)=argγmini=1∑nL(yi,γ)

  2. 对于 m = 1 到 M:

    • 计算负梯度(伪残差)
      rim=−[∂L(yi,F(xi))∂F(xi)]F=Fm−1 r_{im} = - \left[ \frac{\partial L(y_i, F(x_i))}{\partial F(x_i)} \right]{F=F{m-1}} rim=−[∂F(xi)∂L(yi,F(xi))]F=Fm−1

    • 训练回归树 hm(x)h_m(x)hm(x) 拟合伪残差 (xi,rim){(x_i, r_{im})}(xi,rim)

    • 计算最优步长:
      γm=arg⁡min⁡γ∑i=1nL(yi,Fm−1(xi)+γhm(xi)) \gamma_m = \arg\min_{\gamma} \sum_{i=1}^n L(y_i, F_{m-1}(x_i) + \gamma h_m(x_i)) γm=argγmini=1∑nL(yi,Fm−1(xi)+γhm(xi))

    • 更新模型:
      Fm(x)=Fm−1(x)+ν⋅γmhm(x) F_m(x) = F_{m-1}(x) + \nu \cdot \gamma_m h_m(x) Fm(x)=Fm−1(x)+ν⋅γmhm(x)

  3. 输出 FM(x)F_M(x)FM(x)

3.3 伪残差的直观理解

伪残差 :损失函数对预测值的负梯度,表示当前模型预测的错误方向和程度

不同损失函数的伪残差

损失函数 伪残差公式 说明
平方损失(回归) r=y−F(x)r = y - F(x)r=y−F(x) 真实残差
绝对损失(回归) r=sign(y−F(x))r = \text{sign}(y - F(x))r=sign(y−F(x)) 符号残差
对数损失(分类) r=y−p(x)r = y - p(x)r=y−p(x) 概率残差

3.4 学习率(Shrinkage)

学习率 ν\nuν :控制每棵树的贡献,防止过拟合。
Fm(x)=Fm−1(x)+μ⋅γmhm(x) F_m(x)=F_{m−1}(x) + \mu ⋅ \gamma_m h_m(x) Fm(x)=Fm−1(x)+μ⋅γmhm(x)
典型值:0.01 - 0.1

效果

  • 小学习率 + 多棵树 = 更好泛化
  • 需要更多训练时间

第四部分:AdaBoost vs GBDT vs 随机森林

4.1 三者的核心区别

特性 随机森林 AdaBoost GBDT
集成方式 Bagging(并行) Boosting(串行) Boosting(串行)
样本采样 Bootstrap(均匀) 加权采样 全部使用(加权)
基学习器 完整决策树 决策树桩 浅层决策树
模型权重 平等 根据误差加权 学习率控制
过拟合风险 中高
对异常值 鲁棒 敏感 中等
可解释性 中等 较差 较差

4.2 性能对比

数据集类型 推荐算法 原因
高维稀疏 随机森林 对噪声特征鲁棒
低维稠密 GBDT 能捕捉复杂交互
有异常值 随机森林 对异常值不敏感
需要概率输出 GBDT 天然支持概率
小数据集 AdaBoost 不易过拟合

4.3 选择指南

python 复制代码
# 决策树
if 需要可解释性:
    if 数据量小:
        return "决策树"
    else:
        return "随机森林(可解释性较弱)"

if 追求最高精度:
    if 数据量大:
        return "XGBoost / LightGBM(GBDT变体)"
    else:
        return "GBDT / AdaBoost"

if 对异常值敏感:
    return "随机森林"

if 特征维度高且稀疏:
    return "随机森林 / 线性模型"

第五部分:GBDT 核心超参数

5.1 关键参数

参数 含义 典型值 影响
n_estimators 树的数量 100-1000 越多越稳定
learning_rate 学习率 0.01-0.1 越小越需要更多树
max_depth 最大深度 3-8 控制交互复杂度
min_samples_split 分裂最小样本数 2-20 正则化
subsample 子采样比例 0.5-1.0 随机性,防过拟合
loss 损失函数 'log_loss' 任务类型

5.2 参数交互

学习率与树数量的权衡

python 复制代码
# 大学习率 + 少树
gbdt = GradientBoostingClassifier(learning_rate=0.3, n_estimators=50)

# 小学习率 + 多树(通常更好)
gbdt = GradientBoostingClassifier(learning_rate=0.05, n_estimators=300)

经验法则

  • 学习率 × 树数量 ≈ 常数
  • 小学习率(<0.1)通常更好

5.3 正则化参数

参数 作用 建议
subsample 每次迭代采样比例 0.5-0.8
max_depth 限制树深度 3-6
min_samples_split 分裂最小样本 5-20
min_samples_leaf 叶节点最小样本 2-10
max_features 特征子集 'sqrt'

第六部分:损失函数与优化

6.1 常用损失函数

任务 损失函数 sklearn参数 说明
二分类 对数损失 loss='log_loss' 输出概率
二分类 指数损失 loss='exponential' 类似AdaBoost
回归 平方损失 loss='ls' 对异常值敏感
回归 绝对损失 loss='lad' 鲁棒
回归 Huber损失 loss='huber' 平衡

6.2 损失函数选择

python 复制代码
# 二分类(默认,推荐)
gbdt = GradientBoostingClassifier(loss='log_loss')

# 类似AdaBoost(对异常值更敏感)
gbdt = GradientBoostingClassifier(loss='exponential')

# 回归 - 平方损失
gbr = GradientBoostingRegressor(loss='ls')

# 回归 - 绝对损失(鲁棒)
gbr = GradientBoostingRegressor(loss='lad')

6.3 早停(Early Stopping)

原理:当验证集性能不再提升时停止训练。

python 复制代码
gbdt = GradientBoostingClassifier(
    n_estimators=1000,
    validation_fraction=0.1,  # 10%数据作为验证集
    n_iter_no_change=10,       # 10轮不提升则停止
    tol=1e-4                   # 提升阈值
)
相关推荐
Little At Air2 小时前
C++stack模拟实现
linux·开发语言·c++·算法
张祥6422889042 小时前
导数与微分有啥区别
算法·数学建模
葳_人生_蕤2 小时前
hot100——图
数据结构·算法
Rust研习社2 小时前
深入浅出 Rust 泛型:从入门到实战
开发语言·后端·算法·rust
数智工坊2 小时前
R-CNN目标检测算法精读全解
网络·人工智能·深度学习·算法·目标检测·r语言·cnn
zs宝来了3 小时前
PyTorch DDP:分布式训练与梯度同步
机器学习·ai·基础设施
MediaTea3 小时前
Scikit-learn:一个最小机器学习工作流示例
人工智能·python·机器学习·scikit-learn
yi.Ist3 小时前
2025CCPC郑州邀请赛
c++·学习·算法·acm
少许极端3 小时前
算法奇妙屋(四十八)-单调栈
java·算法·单调栈