跳到内容

6.2 Bagging、随机森林与 OOB:平均只能消除彼此不完全相同的误差

模型工坊训练了几棵深树。它们在训练集上几乎没有错误,换一次抽样却会在根节点选择不同特征。情报官没有要求“找出唯一正确的树”,而是让多棵树分别判断,再把它们的概率汇总。

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

本课目标

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

1. Bagging 的训练与预测

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

对 $B$ 个回归器:

$$ \hat f_{bag}(x)=\frac1B\sum_{b=1}^B\hat f_b(x). $$

分类通常平均各树的类别概率,再按阈值/最大概率行动,而不只是数硬投票。概率平均保留了更多信息,也便于随后做阈值选择与校准。

2. 为什么“多”还不够

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

$$ \operatorname{Var}(\bar e)=\rho\sigma^2+\frac{1-\rho}{B}\sigma^2. $$

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

因此 Bagging 的关键不只是模型数量,而是:单个模型具备信号,同时误差不能完全相关。

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

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

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

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

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

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

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

下面假设 X_train/X_valid 已经过同一套无泄漏 pipeline,且行可近似视为 iid:

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_ 默认是什么指标取决于 estimator/API 参数,不应只打印一个值就当作完整评估。若需要 OOB 概率,可检查 oob_decision_function_,并确认每行获得了足够多的 OOB 预测。

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

5. OOB 从哪里来

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

$$ \left(1-\frac1n\right)^n\to e^{-1}\approx36.8%. $$

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

但 OOB 不是万能验证集:

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

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

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

树的容量

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

森林大小

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

样本与特征采样

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

类别/样本权重

class_weightsample_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