引言
单个模型(决策树、逻辑回归)常有力不从心的时候:树容易过拟合、线性模型学不动非线性。**集成学习(Ensemble)**把多个「弱模型」组合成一个「强模型」,是几乎所有机器学习竞赛与工业落地的默认武器。本文从偏差-方差视角讲清「为什么集成有效」,再逐步落地 Bagging → 随机森林 → AdaBoost → GBDT → XGBoost/LightGBM → Stacking,全程附 sklearn 可运行代码。
前置:/ml-supervised-classification/(分类指标)、/ml-model-evaluation/(交叉验证与偏差方差)、/ml-decision-tree/(决策树基模型)。本专题聚焦集成方法的组合逻辑与实战。
目录
- 1. 集成为什么有效:偏差方差视角
- 2. Bagging:用并行降低方差
- 3. 随机森林:Bagging 加随机特征
- 4. Boosting:用串行降低偏差
- 5. AdaBoost:给错分样本加权
- 6. 梯度提升 GBDT:用残差拟合
- 7. XGBoost 与 LightGBM 工程实践
- 8. Stacking 与 Blending:元学习器
- 9. 集成实战:完整竞赛流水线
- 10. 速查表与一句话记忆
- 延伸阅读
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 的本质区别
| 维度 | Bagging | Boosting |
|---|---|---|
| 训练 | 并行、独立 | 串行、后依赖前 |
| 目标 | 降方差 | 降偏差 |
| 错误样本 | 不特别对待 | 加大权重/残差 |
| 代表 | 随机森林 | 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 文档
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。