集成学习实战:Bagging、随机森林、梯度提升与 Stacking

集成学习实战全流程:偏差方差视角的集成动机、Bagging 与随机森林、AdaBoost 到 GBDT 的梯度提升思想、XGBoost/LightGBM 工程实践、Stacking 与 Blending 进阶融合、sklearn 端到端实战。

引言

单个模型(决策树、逻辑回归)常有力不从心的时候:树容易过拟合、线性模型学不动非线性。**集成学习(Ensemble)**把多个「弱模型」组合成一个「强模型」,是几乎所有机器学习竞赛与工业落地的默认武器。本文从偏差-方差视角讲清「为什么集成有效」,再逐步落地 Bagging → 随机森林 → AdaBoost → GBDT → XGBoost/LightGBM → Stacking,全程附 sklearn 可运行代码。

前置:/ml-supervised-classification/(分类指标)、/ml-model-evaluation/(交叉验证与偏差方差)、/ml-decision-tree/(决策树基模型)。本专题聚焦集成方法的组合逻辑与实战。


目录


1. 集成为什么有效:偏差方差视角

1.1 单个模型的困境

模型偏差方差表现
线性模型高低欠拟合非线性
深决策树低高过拟合训练集
KNN中高对尺度/维度敏感

集成要同时压住两头:Boosting 主要降偏差,Bagging 主要降方差。

1.2 「三个臭皮匠」的数学直觉

假设 M 个独立模型的误差期望都是 μ,取平均后:

Var(平均) = Var(单个) / M   ← 独立时方差降 M 倍
但模型不独立(同数据训练),降幅变小 → 加入随机性

记忆:集成 = 平均或加权多个弱模型;Bagging 用并行+随机降方差,Boosting 用串行+纠错降偏差。


2. Bagging:用并行降低方差

2.1 自助采样(Bootstrap)

从训练集有放回抽样 M 次,每次抽 n 个样本,得到 M 个子集:

import numpy as np
from sklearn.utils import resample

X_boot = resample(X, y, n_samples=len(X), replace=True)

每个子集会缺约 37% 的原始样本(袋外样本 OOB),恰好用来无偏验证。

2.2 Bagging 训练与预测

from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier

bag = BaggingClassifier(
    estimator=DecisionTreeClassifier(max_depth=None),
    n_estimators=50, bootstrap=True, oob_score=True, random_state=42)
bag.fit(X_train, y_train)
print("OOB 分数:", bag.oob_score_.round(3))   # 不需单独验证集

记忆:Bagging 三步——有放回抽样出 M 个子集、各子集独立训模型、投票/平均聚合;OOB 样本免费当验证集。


3. 随机森林:Bagging 加随机特征

3.1 为什么还要随机特征

Bagging 只在样本上随机,树之间仍可能高度相似(特征相同)。随机森林在每次分裂时只随机考察部分特征,进一步降低树间相关性。

from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(
    n_estimators=200, max_depth=10,
    max_features='sqrt',     # 每次分裂随机取 sqrt(n_features) 个特征
    min_samples_leaf=4, random_state=42)
rf.fit(X_train, y_train)

3.2 特征重要性与调参要点

参数作用典型值
n_estimators树数,越大越稳100-500
max_depth深度限制,防过拟合5-15 或 None
max_features每分裂随机特征数sqrt / log2
min_samples_leaf叶最少样本2-8
importances = pd.Series(rf.feature_importances_, index=X.columns).sort_values(ascending=False)
print(importances.head(10))

记忆:随机森林 = Bagging + 随机特征选择;max_features 是关键旋钮,调深 + 大森林搭配 min_samples_leaf 防过拟合。


4. Boosting:用串行降低偏差

4.1 与 Bagging 的本质区别

维度BaggingBoosting
训练并行、独立串行、后依赖前
目标降方差降偏差
错误样本不特别对待加大权重/残差
代表随机森林AdaBoost / GBDT / XGBoost

4.2 Boosting 通用套路

第1棵树:正常训练
第2棵树:重点学「第1棵没学好的样本」
第3棵树:重点学「前2棵联合的错误」
...
最终:加权组合所有树

记忆:Boosting 串行纠错——每一棵新树专攻前面的短板,最终加权投票;树越强整体越强,但要控学习率防过拟合。


5. AdaBoost:给错分样本加权

5.1 权重更新思想

每一轮:加大被分错样本的权重,让下一棵树优先照顾它们。

from sklearn.ensemble import AdaBoostClassifier

ada = AdaBoostClassifier(
    estimator=DecisionTreeClassifier(max_depth=1),   # 弱分类器(桩)
    n_estimators=200, learning_rate=0.5, random_state=42)
ada.fit(X_train, y_train)

5.2 AdaBoost 优缺点

优点缺点
简单、无需调参多对噪声敏感(噪声会被无限加权)
理论误差上界好弱学习器不能太强

记忆:AdaBoost = 弱桩串行 + 错分样本加权;对噪声敏感,强噪声数据改用 GBDT/XGBoost。


6. 梯度提升 GBDT:用残差拟合

6.1 从「权重」到「残差」

AdaBoost 对分类给样本加权;GBDT 对回归/分类直接拟合负梯度(残差)——每棵树学的是「前面所有树的残差」,而不是原始标签。

from sklearn.ensemble import GradientBoostingClassifier

gbdt = GradientBoostingClassifier(
    n_estimators=200, learning_rate=0.05,
    max_depth=3, subsample=0.8, random_state=42)
gbdt.fit(X_train, y_train)

6.2 学习率与树数的配合

学习率小 + 树数多 → 慢而稳(推荐)
学习率大 + 树数少 → 快而险
best_estimators 可用早停自动定
gbdt = GradientBoostingClassifier(
    n_estimators=500, learning_rate=0.03, max_depth=3,
    validation_fraction=0.15, n_iter_no_change=20, random_state=42)
gbdt.fit(X_train, y_train)
print("早停于树数:", gbdt.n_estimators_)

记忆:GBDT 每棵树拟合前面树的残差;learning_rate 越小越稳,配早停自动选树数;subsample 加随机性防过拟合。


7. XGBoost 与 LightGBM 工程实践

7.1 XGBoost 亮点

  • 二阶泰勒展开(比一阶梯度更准)
  • 内置正则(γ、λ)天然防过拟合
  • 加权分位数 + 稀疏感知,处理缺失值友好
  • 原生支持早停、交叉验证、GPU
import xgboost as xgb

xgb_model = xgb.XGBClassifier(
    n_estimators=300, learning_rate=0.05,
    max_depth=6, subsample=0.8, colsample_bytree=0.8,
    reg_lambda=1.0, early_stopping_rounds=30, random_state=42)
xgb_model.fit(X_train, y_train, eval_set=[(X_val, y_val)], verbose=False)

7.2 LightGBM 亮点

  • 直方图分箱 + leaf-wise 生长,速度快
  • 原生类别特征支持
  • 内存占用低,大数据友好
import lightgbm as lgb

lgb_model = lgb.LGBMClassifier(
    n_estimators=300, learning_rate=0.05, num_leaves=31,
    feature_fraction=0.8, bagging_fraction=0.8, random_state=42)
lgb_model.fit(X_train, y_train, eval_set=[(X_val, y_val)],
              callbacks=[lgb.early_stopping(30)], eval_metric='auc')

7.3 三大库选型速查

库场景备注
sklearn GBDT中小数据快速原型参数简单
XGBoost数据质量参差/需正则强默认值、成熟稳定
LightGBM大数据/类别特征多最快、省内存

记忆:XGBoost 二阶梯度+正则更准更稳;LightGBM 直方图+leaf-wise 更快;中小数据 sklearn、大数据 LightGBM、要稳健用 XGBoost。


8. Stacking 与 Blending:元学习器

8.1 思路

第一层:多个不同模型各自预测;第二层:用它们的预测作为特征,再训练一个元学习器。

8.2 Blending(简单版)

# 第一层预测作为新特征
meta_X = pd.DataFrame({
    'rf': rf.predict_proba(X)[:, 1],
    'xgb': xgb_model.predict_proba(X)[:, 1],
    'lgb': lgb_model.predict_proba(X)[:, 1],
})
# 第二层
from sklearn.linear_model import LogisticRegression
meta = LogisticRegression().fit(meta_X, y)

8.3 Stacking(交叉验证版,防过拟合)

用交叉验证生成第一层的 OOF 预测,避免「用训练集预测自己」造成的泄漏:

from sklearn.ensemble import StackingClassifier
from sklearn.linear_model import LogisticRegression

stack = StackingClassifier(
    estimators=[
        ('rf', RandomForestClassifier(n_estimators=100, random_state=42)),
        ('xgb', xgb.XGBClassifier(n_estimators=100, random_state=42)),
        ('lgb', lgb.LGBMClassifier(n_estimators=100, random_state=42)),
    ],
    final_estimator=LogisticRegression(),
    cv=5, stack_method='predict_proba')
stack.fit(X_train, y_train)

记忆:Stacking 分两层——底层多个异质模型出预测,顶层元学习器组合;必须用交叉验证的 OOF 预测当特征,否则自预测泄漏。


9. 集成实战:完整竞赛流水线

9.1 三步套路

① 基模型调参(rf/xgb/lgb 各调一轮 CV)
② 异质集成(不同算法、不同随机种子、不同特征子集)
③ 融合(加权平均 → 可再上 Stacking)

9.2 加权平均代码

from sklearn.metrics import roc_auc_score

preds = np.column_stack([
    rf_oof, xgb_oof, lgb_oof])          # 各模型 OOF 概率
# 网格搜权重
best_w, best_auc = None, 0
for w in np.arange(0, 1.05, 0.05):
    p = w*preds[:,0] + (1-w)/2*(preds[:,1]+preds[:,2])
    auc = roc_auc_score(y, p)
    if auc > best_auc: best_w, best_auc = w, auc
print("最优权重:", best_w, "AUC:", best_auc.round(4))

9.3 避免踩坑

  • 权重别在测试集上调(过拟合测试集)
  • Stacking 的 cv 参数与数据划分保持一致
  • 特征泄漏:做任何编码/填补前先划分

记忆:实战三步——各自调参到最优、异质集成(不同算法/种子/特征)、加权或 Stacking 融合;融合参数只在验证集上调。


10. 速查表与一句话记忆

方法机制主要降适用
Bagging并行自助抽样方差高方差模型
随机森林Bagging+随机特征方差通用默认
AdaBoost错分加权偏差低噪声小数据
GBDT残差拟合偏差表格数据通用
XGBoost二阶梯度+正则偏差稳健首选
LightGBM直方图加速偏差大数据/类别特征
Stacking两层元学习两者竞赛/精度至上

一句话记忆:集成 = 组合多个弱模型——Bagging 用并行+随机降方差(随机森林),Boosting 用串行纠错降偏差(GBDT/XGBoost/LightGBM 拟合残差),Stacking 用第一层预测当特征交给元学习器融合;实战按「各自调参 → 异质集成 → 加权/Stacking 融合」三步走,融合参数只在验证集上调。


延伸阅读

  • /ml-model-evaluation/ — 交叉验证与偏差方差基础
  • /ml-supervised-classification/ — 分类评估指标
  • /ml-feature-engineering/ — 特征侧优化与集成协作
  • /ml-automl-hpo/ — 集成模型超参自动调优
  • [[ai-ml]] — 算法原理深度专题
  • scikit-learn Ensemble 文档

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「ml」更多文章

  1. 迁移学习实战:预训练模型、特征提取与微调全流程
  2. 计算机视觉入门实战:图像处理与 CNN 图像分类
  3. 深度学习进阶:CNN、RNN、正则化与训练调参实战