从零开始学AI22——集成学习

集成学习核心思想是"三个臭皮匠,顶个诸葛亮",通过组合多个弱模型提升整体性能。三大流派:Bagging(如随机森林)并行训练、投票降方差,适合抗噪稳定场景;Boosting(如XGBoost)串行纠错、逐次优化,精准度高;Stacking多层融合,专家会诊,追求极致精度。在结构化数据领域,集成学习(尤其XGBoost、随机森林)是工业界与竞赛首选,广泛应用于风控、推荐、广告点击率预测等任务。非结构化数据(图像、语音)则由深度学习主导。数学本质:Bagging降低方差,Boosting通过梯度下降减偏差。代码实证显示,GBDT通过不断拟合残差逼近最优解,效果显著。

简单理解

集成学习 (Ensemble Learning) 的核心思想就一句话:"三个臭皮匠,顶个诸葛亮"。

在机器学习里,我们不仅可以训练一个 模型(比如一棵决策树),我们还可以训练一大堆 模型,然后让它们组团来做决定。

通常,这一大堆模型(臭皮匠)合起来的效果,会比单独任何一个模型(哪怕是诸葛亮)都要好。


集成学习的"三大门派"

根据这堆模型怎么组团,集成学习分成了三个主要流派:

1. Bagging (装袋法) ------ "民主投票"
  • 代表作: 随机森林 (Random Forest)
  • 口号: 大家各学各的,最后投票。
  • 怎么做:
    1. 找 100 个学生(模型)。
    2. 给每个学生发不一样的复习资料(随机采样训练数据)。
    3. 大家同时开始独立学习(并行训练),互不干扰。
    4. 考试时,大家一起做同一道题。
    5. 结果: 少数服从多数。如果 80 人选 A,20 人选 B,那就选 A。
  • 优点: 极其稳定!就算有个别学生学傻了(过拟合),大部分人还是正常的,整体结果不会跑偏。
2. Boosting (提升法) ------ "接力补课"
  • 代表作: AdaBoost, GBDT, XGBoost, LightGBM
  • 口号: 专门盯着错题学。
  • 怎么做:
    1. 先让第 1 个学生做题。
    2. 第 1 个学生做错 的题目,会被挑出来,加倍重视。
    3. 第 2 个学生专门去学这部分做错的题。
    4. 第 2 个学生又做错的题,交给第 3 个学生去攻克......
    5. 结果: 是一步步串行训练出来的。
  • 优点: 极其精准!后面的学生都是为了弥补前面学生的不足而存在的,所以准确率通常比 Bagging 更高(打比赛的神器)。
3. Stacking (堆叠法) ------ "专家会诊"
  • 代表作: 各类比赛的冠军方案常用。
  • 口号: 用一个老板来管这帮打工的。
  • 怎么做:
    1. 第一层:训练一堆不同的模型(SVM、决策树、神经网络...),让它们分别预测结果。
    2. 第二层:训练一个**"元模型" (Meta-Model)**(通常是逻辑回归)。
    3. 结果: 第二层的模型把第一层所有模型的预测结果当作输入特征,学习如何组合它们才能得到最佳答案。
    4. 比如:老板发现 A 模型擅长做数学,B 模型擅长做语文,老板就会根据题目类型,动态分配权重。

一句话总结

  • Bagging (随机森林): 并行训练,少数服从多数,为了防过拟合(降方差)。
  • Boosting (XGBoost): 串行训练,死磕错题,为了提准确率(降偏差)。
  • Stacking: 多层结构,集百家之长,为了刷榜拿冠军。

应用场景

集成学习(尤其是 Random Forest 和 XGBoost/LightGBM )是目前工业界和竞赛圈的绝对主力。

在深度学习(Deep Learning)统治图像和语音领域的同时,集成学习统治了几乎所有的表格数据(Tabular Data)领域。

只要你的数据是存放在 Excel 或 SQL 数据库里的结构化数据,首选一定是集成学习。


1. 随机森林 (Random Forest) 的应用场景

关键词: 稳定、抗噪、无脑好用(不用调参效果也不错)。

  • 金融风控(银行/互金):
    • 场景: 信用卡反欺诈、贷款违约预测。
    • 优势: 银行数据通常噪音很大(脏数据多),且对稳定性要求极高。随机森林不容易受异常值影响,哪怕有个别数据填错了,几十棵树投票也能把错误抵消掉。
  • 医疗病理分析:
    • 场景: 基因测序分类、疾病预测。
    • 优势: 医疗数据通常特征维度极高(几万个基因),样本数却很少(几百个病人)。随机森林处理高维数据能力强,且能给出特征重要性 (Feature Importance),告诉医生哪个基因最关键。
  • 电商推荐系统的粗排(Recall):
    • 场景: 从百万商品里快速筛选出几千个候选集。
    • 优势: 可以并行计算,速度快,适合处理大规模数据。

2. XGBoost / LightGBM 的应用场景

关键词: 精准、快、打比赛神器、工业界核心。

(这是目前数据挖掘岗位的必备技能)

  • 搜索与广告点击率预估 (CTR Prediction):
    • 场景: 决定给用户展示哪个广告,或者淘宝搜出来什么商品排在前面。
    • 优势: 这种场景对准确率要求极高(提升 0.1% 的点击率就是几亿的收入)。Boosting 算法通过死磕残差(Residual),能把预测误差压到极致。
  • 销售预测 / 库存管理:
    • 场景: 预测下个月这件衣服能卖多少件?
    • 优势: 这类问题通常包含时间序列特征和各种复杂的非线性关系。GBDT 类算法能很好地拟合这些非线性规律。
  • 数据竞赛 (Kaggle/天池):
    • 场景: 几乎所有非图像/视频类的比赛。
    • 地位: 如果你打比赛不用 XGBoost/LightGBM/CatBoost,你基本进不了前 10%。它们就是当今表格数据领域的"屠龙刀"。

3. Stacking 的应用场景

关键词: 刷分、极致精度、复杂。

  • 高精尖的预测任务:
    • 场景: 顶级对冲基金的股价预测、地震波预测、精密仪器故障预测。
    • 优势: 当单一模型(无论是 XGBoost 还是 神经网络)都无法再提升哪怕 0.001 的精度时,就把它们堆叠起来(Stacking)。虽然训练很慢、模型很重、部署很麻烦,但在赢者通吃的领域,这点提升值得付出代价。

集成学习什么时候不好用?

  1. 非结构化数据:
    • 图像、视频、音频: 这些领域是 CNN/Transformer(深度学习)的天下。集成学习处理像素级别的特征效果很差。
  2. 自然语言处理 (NLP):
    • 虽然以前有用,但现在基本也被 BERT/GPT(Transformer)取代了。
  3. 对实时性要求极高且资源受限(如嵌入式设备):
    • 虽然 LightGBM 已经很快了,但如果要在一块小芯片上跑几千棵树,内存和耗电量可能还是扛不住。这时候简单的逻辑回归 或单棵决策树可能更合适。

总结

  • 处理 Excel 表格数据? →→ XGBoost / LightGBM (首选)。
  • 数据太脏、怕过拟合? →→ 随机森林。
  • 处理图片/声音? →→ 左转去找 深度学习。

数学推导

集成学习的数学推导主要分为两派:

  1. Bagging (随机森林) 的推导核心是统计学中的偏差-方差分解 (Bias-Variance Decomposition)。
  2. Boosting (GBDT/XGBoost) 的推导核心是加法模型 (Additive Model) 和 前向分步算法 (Forward Stagewise Algorithm)。

我们重点讲这两个核心逻辑。


一、 Bagging 的数学原理:降低方差 (Variance Reduction)

核心问题: 为什么把一堆"差不多"的模型平均一下,效果就会变好?

假设我们有 nn 个独立的随机变量(模型预测值) X1,X2,...,XnX1​,X2​,...,Xn​。

假设它们都服从正态分布,方差都是 σ2σ2。

  1. 单个模型的方差:

    Var(Xi)=σ2Var(Xi​)=σ2

    (这意味着单个模型很容易受数据波动影响,发挥不稳定)

  2. 集成模型的方差(取平均):

    令 Xˉ=1n∑XiXˉ=n1​∑Xi​。

    根据方差的性质(独立变量和的方差等于方差的和):

    Var(Xˉ)=Var(1n∑Xi)=1n2∑Var(Xi)=1n2⋅nσ2=σ2nVar(Xˉ)=Var(n1​∑Xi​)=n21​∑Var(Xi​)=n21​⋅nσ2=nσ2​

推导结论:

通过对 nn 个独立模型取平均,整体的方差变成了原来的 1nn1​ !

这就是随机森林为什么特别稳的数学原因。它通过"民主投票"极大地降低了模型的**过拟合(高方差)**风险。

(注:实际中模型很难完全独立,所以方差降低幅度没有 1/n 这么完美,但依然效果显著)


二、 Boosting 的数学原理:拟合残差 (Residual Fitting)

核心问题: 为什么一个个接力学,就能越来越准?

Boosting 的本质是一个加法模型 :

Fm(x)=∑t=1mαtht(x)Fm​(x)=∑t=1m​αt​ht​(x)

  • Fm(x)Fm(x):最终的强学习器。
  • ht(x)ht(x):第 tt 步训练出来的弱学习器(小树)。
  • αtαt:第 tt 棵树的权重。

我们以 GBDT (Gradient Boosting Decision Tree) 为例,它的推导最直观。

推导过程:

  1. 第一步: 训练第一棵树 h1(x)h1​(x) 去拟合真实值 yy。

    • 预测值:F1(x)=h1(x)F1(x)=h1(x)
    • 残差 (Residual): r1=y−F1(x)r1=y−F1(x)
  2. 第二步: 训练第二棵树 h2(x)h2​(x)。

    • 关键点: 这棵树的目标不再是拟合 yy,而是拟合残差 r1r1​。
    • 它想让 h2(x)≈y−F1(x)h2(x)≈y−F1(x)。
    • 更新强模型:F2(x)=F1(x)+h2(x)F2(x)=F1(x)+h2(x)。
  3. 第 m 步(数学泛化):

    我们定义一个损失函数 L(y,F(x))L(y,F(x)) (比如均方误差)。

    我们要找到第 mm 棵树 hmhm​,使得加入它之后,整体损失 LL 最小。

    利用泰勒展开 (一阶展开):

    L(y,Fm−1(x)+hm(x))≈L(y,Fm−1(x))+∂L∂F⋅hm(x)L(y,Fm−1​(x)+hm​(x))≈L(y,Fm−1​(x))+∂F∂L​⋅hm​(x)

    为了让损失变小(小于上一轮的损失),我们需要让这一项变负:

    ∂L∂F⋅hm(x)<0∂F∂L​⋅hm​(x)<0

    最快让它变负的方法,就是让 hm(x)hm​(x) 沿着负梯度方向 走:

    hm(x)≈−∂L(y,Fm−1(x))∂Fm−1(x)hm​(x)≈−∂Fm−1​(x)∂L(y,Fm−1​(x))​

推导结论:

GBDT 的每一棵新树,都在拟合上一轮模型的负梯度 (对于均方误差来说,负梯度正好就是残差 y−y^y−y^​)。

通过不断地把"负梯度"加进去,总误差就会一步步趋近于 0。

  • XGBoost 的改进: 它在泰勒展开时,保留了二阶导数(Hessian矩阵),不仅看梯度下降的方向,还看曲率,所以走得更准、更快。

三、 总结对比

维度 Bagging (随机森林) Boosting (GBDT/XGBoost)
数学目标 降低方差 (Variance) 降低偏差 (Bias)
模型关系 并行独立 (iid) 串行依赖 (Sequential)
核心操作 平均 / 投票 梯度下降 (在函数空间)
推导逻辑 统计学大数定律 优化理论 (泰勒展开)

一句话总结数学本质:

  • Bagging 是通过平摊风险来求稳。
  • Boosting 是通过梯度下降来求准。

代码实例

我们将通过一个**波士顿房价预测(回归任务)**的案例,手写实现 Boosting (GBDT) 的核心逻辑,并与 Sklearn 的标准库进行对比。

我们将深入到"残差"层面,让你亲眼看到每一棵树是如何去拟合上一棵树剩下的"烂摊子"的。

Python 代码实现

请确保安装了 sklearn, numpy, matplotlib。

python 复制代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import GradientBoostingRegressor, RandomForestRegressor
from sklearn.metrics import mean_squared_error
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split

# ==========================================
# 1. 准备数据 (加州房价数据集)
# ==========================================
# 为了方便演示和画图,我们只取前 500 个样本,且只用 1 个特征 (MedInc: 收入中位数)
housing = fetch_california_housing()
X = housing.data[:500, [0]]  # 只取第0列特征
y = housing.target[:500]     # 房价

# 排序 X 以便画图好看 (不影响训练)
sort_idx = X.flatten().argsort()
X = X[sort_idx]
y = y[sort_idx]

# 划分训练测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# ==========================================
# 2. 手写 GBDT (Gradient Boosting) 核心逻辑
# ==========================================
print(">>> 手写 GBDT 训练过程展示")

# 超参数
n_estimators = 3    # 我们只训练 3 棵树,方便一步步看
learning_rate = 1.0 # 学习率设为 1.0 (为了让效果更明显)

# 存储每一棵小树
trees = []
# 初始预测值 (通常设为 y 的平均值,这里简化为 0)
f_m = np.zeros(len(y_train)) 

plt.figure(figsize=(15, 5))

# --- 开始串行训练 ---
for i in range(n_estimators):
    # 1. 计算残差 (Residual)
    # 核心公式: r = y_true - y_current_pred
    # 对于均方误差(MSE),负梯度正好就是残差
    residuals = y_train - f_m
    
    # 2. 训练一棵小树去拟合这个残差 (不是拟合 y !)
    # 这里的树深度通常很浅 (weak learner)
    tree = DecisionTreeRegressor(max_depth=2, random_state=42)
    tree.fit(X_train, residuals)
    trees.append(tree)
    
    # 3. 更新强学习器的预测值
    # F_new(x) = F_old(x) + lr * tree.predict(x)
    r_pred = tree.predict(X_train)
    f_m += learning_rate * r_pred
    
    # --- 可视化这一步 ---
    plt.subplot(1, 3, i+1)
    # 画出残差数据点
    plt.scatter(X_train, residuals, color='r', marker='+', label='Residuals (Errors)')
    # 画出这棵树拟合的曲线
    # 为了画平滑曲线,生成一点测试数据
    X_plot = np.linspace(X.min(), X.max(), 100).reshape(-1, 1)
    y_plot = tree.predict(X_plot)
    plt.plot(X_plot, y_plot, 'g-', linewidth=3, label=f'Tree {i+1} Fitting')
    
    plt.title(f"Step {i+1}: Fitting Residuals\nResidual Range: [{residuals.min():.1f}, {residuals.max():.1f}]")
    plt.xlabel("Feature (Income)")
    plt.legend()
    plt.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

# --- 手写模型的最终预测 ---
y_pred_manual = np.zeros(len(y_test))
for tree in trees:
    y_pred_manual += learning_rate * tree.predict(X_test)

mse_manual = mean_squared_error(y_test, y_pred_manual)
print(f"手写 GBDT (3棵树) MSE: {mse_manual:.4f}")


# ==========================================
# 3. 对比 Sklearn 官方实现
# ==========================================
print("\n>>> Sklearn 官方模型对比")

# GBDT
gbdt = GradientBoostingRegressor(n_estimators=3, learning_rate=1.0, max_depth=2, random_state=42)
gbdt.fit(X_train, y_train)
y_pred_gbdt = gbdt.predict(X_test)
mse_gbdt = mean_squared_error(y_test, y_pred_gbdt)
print(f"Sklearn GBDT (3棵树) MSE: {mse_gbdt:.4f}")

# 随机森林 (Bagging 对比)
rf = RandomForestRegressor(n_estimators=3, max_depth=2, random_state=42)
rf.fit(X_train, y_train)
y_pred_rf = rf.predict(X_test)
mse_rf = mean_squared_error(y_test, y_pred_rf)
print(f"Sklearn RF   (3棵树) MSE: {mse_rf:.4f}")

# ==========================================
# 4. 最终效果可视化 (整体拟合曲线)
# ==========================================
plt.figure(figsize=(10, 6))
plt.scatter(X_test, y_test, color='black', alpha=0.5, label='True Data')

# 为了画线
X_grid = np.linspace(X.min(), X.max(), 500).reshape(-1, 1)

# GBDT 预测线
y_grid_gbdt = gbdt.predict(X_grid)
plt.plot(X_grid, y_grid_gbdt, 'r-', linewidth=2, label='GBDT Prediction')

# RF 预测线
y_grid_rf = rf.predict(X_grid)
plt.plot(X_grid, y_grid_rf, 'b--', linewidth=2, label='Random Forest Prediction')

plt.title("GBDT vs Random Forest Fitting Curve")
plt.xlabel("MedInc")
plt.ylabel("House Price")
plt.legend()
plt.show()

代码深度解析

1. 手写 GBDT 的三张子图

运行代码后,你会看到三张连着的图,这就是 Boosting 的灵魂:

  • Step 1: 第一棵树在拟合原始数据的误差。此时残差很大(比如在 -2 到 2 之间)。
  • Step 2: 第二棵树不看原始房价了,它只看 Step 1 剩下的残差。你会发现 Y 轴的范围变小了(误差变小了)。
  • Step 3: 第三棵树继续拟合 Step 2 剩下的残差。
  • 结论: 每一棵树都在做一个"修补匠",把上一棵树没预测准的地方(残差)给补上。最后把这三棵树的预测值加起来,就是一个很准的预测。
2. GBDT vs RF 的对比

在最后的对比图中:

  • Random Forest (蓝虚线): 线条通常比较平滑(或阶梯状更明显),因为它是在取平均,倾向于"中庸",方差小。
  • GBDT (红实线): 线条会试图去捕捉数据的每一个拐点(拟合得更紧密),因为它在不断修正误差,偏差小。
3. 为什么 Sklearn 和手写结果略有不同?

你会发现 mse_manual 和 mse_gbdt 非常接近但不是完全一样(比如 0.98 vs 0.96)。

这是因为 Sklearn 的 GradientBoostingRegressor 在内部做了一些初始化优化(比如初始预测值不是 0,而是训练集的均值或中位数),而且分裂节点的算法细节可能有微小差异。但核心的"拟合残差"逻辑是完全一致的。

相关推荐
天天被压力32 分钟前
【A股分钟级高频数据完全手册 #01】Pro版接口体系总览与REST鉴权:42篇地图与从0接入
java·人工智能·python
IT_陈寒35 分钟前
React实战技巧总结
前端·人工智能·后端
一缕82年的清风35 分钟前
被中产唾弃的“十元快剪”,藏着最狠的极客工程学
人工智能·设计模式
Yyyyyy~1 小时前
【深度学习】day2
人工智能·深度学习
ck0135791 小时前
视频片段提取与视频修剪的区别:多时间段选择及导出流程
人工智能·音视频·视频
沐飞工具箱1 小时前
游戏、漫画、视频里的外语怎么实时翻译?从 OCR + AI 原理聊聊 VoriTrans 屏幕翻译
人工智能·游戏·实时互动·音视频·自动翻译
深蓝AI3 小时前
Postman 静默改装你的编码 Agent:一份 SEVERE issue 里的六条证据链
人工智能·程序员
QY_Research_7 小时前
2026房地产NFT平台创业机遇与落地指南分析报告
大数据·人工智能·物联网·机器人·制造
机器人零零壹8 小时前
技术白皮书:iRobotCAM如何解决机器人激光切割应用中的核心难点,从CAD离线编程到双目视觉定位与轨迹自适应提升复杂空间曲线切割的精度、效率与柔性化水平
人工智能·算法