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. 随机森林怎样降低相关性
随机森林通常结合两个随机源:
- 每棵树使用不同 bootstrap sample;
- 每个节点只在随机抽取的特征子集中寻找最佳分裂。
max_features 越小,树之间通常越不相似,但单棵树也可能更弱。最优平衡由特征冗余、样本量和目标损失决定。
几个相近模型不要混为一谈:
- Bagging tree:bootstrap 行,节点可查看全部特征;
- Random forest:bootstrap 行,并在每个节点随机选择候选特征;
- Extra Trees:还会更随机地选择候选阈值,具体抽样行为看实现参数。
4. 一个可复现的训练骨架
下面假设 X_train/X_valid 已经过同一套无泄漏 pipeline,且行可近似视为 iid:
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_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 数据上随机打乱某列,观察模型分数下降:
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_是客观特征价值:它是有偏的模型使用统计。- 随机森林必须把单树长到最大:树容量需要验证。
- 不标准化就等于不需要前处理:类别、缺失、时间与数据泄漏仍需处理。
练习
- 用不同 $B$ 和
max_features记录 validation 误差与树间预测相关性。 - 比较 OOB 与独立 validation;再制造同用户多行数据观察泄漏。
- 加入一个高基数噪声列,比较 MDI 与 held-out permutation importance。
- 测量森林大小、峰值内存、单请求延迟和批量吞吐。
小结
Bagging 通过平均降低不稳定学习器的方差,随机森林用特征随机进一步降低树间相关性。OOB、重要性和概率输出都很有用,但各自回答的问题有限,必须放在正确的数据切分与评估协议中。
下一课不再并行平均独立树,而是顺序添加新树,让每一步沿当前损失的下降方向修正模型。