跳到内容

第 13 卷 / 第 6 章 / 第 2 课

6.2 Bagging、随机森林与 OOB:误差相关性怎样限制平均的收益 ​

一棵深树可能几乎记住训练数据,换一批样本后却连根节点都改了。对重采样训练的多棵树取平均,可以降低这种不稳定性;前提是它们没有整齐划一地犯错。

这就是 Bagging 的核心:对不稳定学习器重复抽样、拟合与平均。随机森林又在每个节点限制候选特征,主动降低树与树之间的相关性。

本课目标 ​

  • 理解 bootstrap aggregation 怎样降低方差;
  • 解释随机森林的样本随机与特征随机;
  • 正确使用 OOB 估计并识别其失效场景;
  • 区分 impurity importance 与 permutation importance;
  • 从准确率之外评估概率、资源成本与部署行为。

1. Bagging 的训练与预测 ​

有 n 行训练数据时,每棵基学习器从这 n 行中有放回抽取 n 次。不同 bootstrap sample 会遗漏一些行,也会重复抽中另一些行。

对 B 个回归器:

f^bag(x)=1B∑b=1Bf^b(x).

分类集成可以采用多数投票,也可以平均类别概率。下方 scikit-learn 森林使用概率平均,保留分数以便后续选择阈值和做校准。

2. 为什么“多”还不够 ​

若每棵树在某个输入处的误差方差都是 σ2,两两相关系数近似为 ρ,平均误差的方差为:

Var(e¯)=ρσ2+1−ρBσ2.

当 B 增大,第二项缩小,相关误差留下。若所有树总在同一批样本、同一强特征上做相似分裂,继续加树的边际收益会很快变小。

例如 σ2=1、ρ=0.2 时,B 从 10 增至 100,方差从 0.28 降到 0.208,趋近 0.2 而非 0。这个计算只讨论方差,不会替模型消除共同的系统偏差。

3. 随机森林怎样降低相关性 ​

随机森林通常结合两个随机源:

  1. 每棵树使用不同 bootstrap sample;
  2. 每个节点只在随机抽取的特征子集中寻找最佳分裂。

max_features 越小,树之间通常越不相似,但单棵树也可能更弱。最优平衡由特征冗余、样本量和目标损失决定。

几个相近模型不要混为一谈:

  • Bagging tree:bootstrap 行,节点可查看全部特征;
  • Random forest:bootstrap 行,并在每个节点随机选择候选特征;
  • Extra Trees:还会更随机地选择候选阈值,具体抽样行为看实现参数。

4. 一个可复现的训练骨架 ​

以下是 Python 3 片段,已用 scikit-learn 1.9.0 核验。需提供独立的训练、验证数组,特征为可直接使用的数值,标签为 0/1,两个集合都含两类。这里假设行近似 IID;为保持下文的 OOB 含义,不先在全部训练行上拟合预处理器。

python
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import log_loss, roc_auc_score

forest = RandomForestClassifier(
    n_estimators=500,
    max_features="sqrt",
    min_samples_leaf=5,
    bootstrap=True,
    oob_score=True,
    n_jobs=1,
    random_state=42,
)
forest.fit(X_train, y_train)

valid_probability = forest.predict_proba(X_valid)[:, 1]
print("validation log loss:", log_loss(y_valid, valid_probability))
print("validation ROC AUC:", roc_auc_score(y_valid, valid_probability))
print("OOB score:", forest.oob_score_)

这里的 oob_score=True 返回 OOB accuracy。计算概率指标应使用 oob_decision_function_,并检查每行是否得到足够 OOB 投票。这是在相应抽样假设下评估森林;若预处理器已看过全部训练行,OOB 不能代替整个 pipeline 的独立验证。

类别列、缺失值和文本特征的预处理仍应封装进训练折内的 pipeline。某个库版本能接受 NaN,不代表所有森林实现都采用相同缺失路由。

5. OOB 从哪里来 ​

一行在单棵树的 n 次有放回抽样中一次都未被抽到的概率是:

(1−1n)n→e−1≈36.8%.

所以可用没有见过该行的树为它生成 out-of-bag 预测。聚合这些预测,能在不额外切出一块数据的情况下估计某些泛化指标。

但 OOB 不是万能验证集:

  • 同一用户/设备的其他行可能已进入那棵树,造成 group leakage;
  • 时间序列 bootstrap 会让未来记录帮助预测过去;
  • 在全数据上先做填补、编码、selection,OOB 也救不了 preprocessing leakage;
  • 调参反复查看 OOB 后,它已参与模型选择,仍需独立 test 做最终估计。

存在群组或时间结构时,优先采用 group/time-aware validation。

6. 主要容量参数怎样相互作用 ​

树的容量 ​

max_depth、min_samples_leaf、max_leaf_nodes 决定单树多细。完全长开的树不是随机森林的定义要求;噪声高、概率估计重要时,较大叶子常更稳定。

森林大小 ​

增加 n_estimators 通常使有限森林的平均更稳定,本身不等同于 boosting 式的逐轮追噪声。但收益会趋于平台,训练、内存和推理成本持续增加。

样本与特征采样 ​

max_samples 控制每棵树看到多少行,max_features 控制节点候选列。两者同时影响单树强度、相关性和成本。

类别/样本权重 ​

class_weight 或 sample_weight 改变分裂目标和叶概率。它们可反映成本/抽样设计,但可能让原始目标分布上的概率失准,需要另行校准。

7. MDI importance 的偏差 ​

许多实现的 feature_importances_ 汇总各特征带来的 mean decrease in impurity(MDI)。它便宜,却有明确限制:

  • 在训练数据上统计,可能奖励过拟合分裂;
  • 候选切分点多的连续/高基数特征容易获得更高重要性;
  • 相关特征会分摊或替代彼此的重要性;
  • 它描述模型怎样使用列,不是列对结果的因果作用。

不要据此直接删除其余特征后再在同一验证集宣称性能提高。

8. Permutation importance 也需要正确问题 ​

在 held-out 数据上随机打乱某列,观察模型分数下降:

python
from sklearn.inspection import permutation_importance

result = permutation_importance(
    forest,
    X_valid,
    y_valid,
    scoring="neg_log_loss",
    n_repeats=20,
    random_state=42,
    n_jobs=1,
)

这估计的是“对这个已经训练好的模型,在当前验证分布中破坏该列会损失多少”。它依然不是因果效应。强相关列中,打乱一列时另一列仍携带同类信号,单列重要性可能都很低。

打乱相关列也可能产生真实数据中不存在的组合,夸大模型对该列的依赖;不能只考虑重要性被低估这一种方向。

可进一步:

  • 对一组相关特征做 grouped permutation;
  • 在多个时间/群组切片重复估计;
  • 用 partial dependence、ICE 或 ALE 研究响应形状,同时说明其分布假设;
  • 结合领域约束与稳定性分析,而非只排一个名次。

9. 概率、校准与阈值 ​

森林概率是许多叶概率的平均。它可能比单树平滑,但不会自动校准。叶子太小、class weighting、分布变化都会影响概率。

评估应分开:

  • discrimination:ROC AUC/AUPRC、排序;
  • probability quality:log loss、Brier、reliability curve;
  • decision:固定容量下的 recall、成本或净收益;
  • stability:不同 fold、时间窗和随机种子的变化。

校准器必须用森林训练时没见过的数据,或使用交叉拟合。

10. 工程成本 ​

树可并行训练和预测,但 n_jobs=-1 不代表资源免费:

  • 训练进程可能复制数据并增加峰值内存;
  • 大量深树会放大模型体积、冷启动和尾延迟;
  • 线上并发与单请求内部并行可能争抢 CPU;
  • 可复现需要固定随机种子、依赖版本和线程设置。

对表格数据,随机森林是值得比较的强 baseline 之一,不是任何任务都必须先选的模型。稀疏高维文本、平滑外推、严格延迟或可加性解释要求可能让线性/GAM/其他方法更合适。

常见误区 ​

  • 加树就能消除所有误差:相关误差和系统偏差仍会保留。
  • OOB 等同独立 test:调参、群组、时间与前处理泄漏都会破坏它。
  • feature_importances_ 是客观特征价值:它是有偏的模型使用统计。
  • 随机森林必须把单树长到最大:树容量需要验证。
  • 不标准化就等于不需要前处理:类别、缺失、时间与数据泄漏仍需处理。

练习 ​

  1. 用不同 B 和 max_features 记录 validation 误差与树间预测相关性。
  2. 比较 OOB 与独立 validation;再制造同用户多行数据观察泄漏。
  3. 加入一个高基数噪声列,比较 MDI 与 held-out permutation importance。
  4. 测量森林大小、峰值内存、单请求延迟和批量吞吐。

小结 ​

Bagging 通过平均降低不稳定学习器的方差,随机森林用特征随机进一步降低树间相关性。OOB、重要性和概率输出都很有用,但各自回答的问题有限,必须放在正确的数据切分与评估协议中。

梯度提升改用顺序加树,让每一步沿当前损失的下降方向修正模型。

Built with VitePress | Software Systems Atlas