跳转到内容
← 返回算法
机器学习算法计算机科学 · 机器学习 · 集成学习19 分钟阅读

随机森林

Random Forests

2001 年,利奥·布雷曼(Leo Breiman)在《机器学习》杂志发表了题为《随机森林》的论文,提出了一个简单但极其有效的思想:一棵决策树不稳定、容易过拟合,但一千棵随机生长的决策树投票,却能得到稳定而准确的预测。 随机森林是当今工业界应用最广泛的机器学习算法之一。它不需要特征缩放,天然处理缺失值,提供特征重要性排…

随机森林集成学习决策树Bagging特征重要性

2001 年,利奥·布雷曼(Leo Breiman)在《机器学习》杂志发表了题为《随机森林》的论文,提出了一个简单但极其有效的思想:一棵决策树不稳定、容易过拟合,但一千棵随机生长的决策树投票,却能得到稳定而准确的预测。

随机森林是当今工业界应用最广泛的机器学习算法之一。它不需要特征缩放,天然处理缺失值,提供特征重要性排名,且几乎不需要调参就能有不错的表现。

破除误解:随机性不是缺点

随机森林的两层随机性——Bootstrap 采样和随机特征选择——初看像是引入了噪声,似乎应该比用全部数据的单棵决策树更差。

实际上恰恰相反。随机性解决了决策树最严重的两个问题:

  1. 高方差(过拟合):单棵决策树对训练数据的细节过度敏感,训练集稍有变化,树的结构就大幅改变。多棵随机树的平均大幅降低方差。
  2. 树之间的相关性:如果只是 Bagging(不引入特征随机性),各树可能选择相同的强特征,高度相关,平均的效益有限。随机特征选择强制树之间的差异化,使平均更有效。

两层随机性

第一层:Bootstrap 采样(行随机)

$n$ 个训练样本中有放回地随机抽取 $n$ 个样本,构成一棵树的训练集。约 36.8% 的样本不会被抽到,成为该树的袋外样本(Out-of-Bag, OOB),用于无偏地估计泛化误差。这个数字不是经验值,是能算出来的,下面有一节专门推它。

第二层:随机特征选择(列随机)

在每个节点分裂时,不考虑所有特征,而是从 $p$ 个特征中随机抽取 $m$(通常 m=pm = \sqrt{p} 用于分类,$m = p/3$ 用于回归),仅在这 $m$ 个特征中选择最优分裂。

预测:多数投票与平均

分类任务:每棵树输出一个类别标签,最终结果取多数票:

y^=mode{h1(x),h2(x),,hB(x)}\hat{y} = \text{mode}\{h_1(x), h_2(x), \ldots, h_B(x)\}

回归任务:每棵树输出一个实数,最终结果取平均:

y^=1Bb=1Bhb(x)\hat{y} = \frac{1}{B} \sum_{b=1}^{B} h_b(x)

手算一次投票:多样性凭什么有用

先看最理想的情形:$B$独立的树,每棵以概率 $p$ 判错。多数票判错的概率就是二项分布的上尾 $P(X > B/2)$XBin(B,p)X \sim \text{Bin}(B, p)

单棵树错误率$B=1$$B=5$$B=11$$B=25$$B=101$
$p = 0.4$0.4000.3170.2470.1540.021
$p = 0.3$0.3000.1630.0780.0171×1051\times10^{-5}

只要 $p < 0.5$,树越多错误率越低,而且降得很快。这就是"弱学习器投票"的全部数学——五棵勉强及格的树凑在一起,错误率从 40% 掉到 31.7%;101 棵掉到 2.1%。

这张表有个致命前提:独立。真实森林里的树都在同一份数据上训练,彼此远不独立。这里有一个把随机森林讲清楚的关键式子:$B$ 个同分布、方差均为 σ2\sigma^2、两两相关系数为 ρ\rho 的预测,其平均值的方差是

Var ⁣(hˉ)=ρσ2+1ρBσ2\mathrm{Var}\!\left(\bar{h}\right) = \rho\sigma^2 + \frac{1 - \rho}{B}\sigma^2

代几个数看(取 σ2=1\sigma^2 = 1):

ρ\rho$B=10$$B=100$$B=1000$BB \to \infty
0.50.5500.5050.50050.5
0.20.2800.2080.20080.2
0.050.1450.05950.05100.05

最后一列就是全部答案:方差有个下限 ρσ2\rho\sigma^2,加树加不下去ρ=0.5\rho = 0.5 时,一万棵树也只能把方差压到单棵树的一半;ρ=0.05\rho = 0.05 时能压到 1/20。第二个可读之处是收敛得多快——$B = 100$ 时三行都已经贴住了各自的下限,这解释了为什么"树从 100 加到 1000"通常几乎没有收益,而很多教程仍在建议这么做。

于是那两层随机性的分工彻底清楚了:Bootstrap 采样让"平均"这个动作有意义,随机特征选择负责压低 ρ\rho。如果不做列随机,所有树都会抢着用同一个最强特征做根节点分裂,ρ\rho 高得离谱,加树几乎无效。列随机迫使树使用不同的特征组合,每棵树单独变弱(σ2\sigma^2 略升、强度略降),但 ρ\rho 大幅下降,净效果是赢的。

布雷曼在 2001 年那篇论文里把这个权衡写成了一条上界:森林的泛化误差满足

PEρˉ(1s2)s2PE^* \leq \frac{\bar{\rho}\,(1 - s^2)}{s^2}

其中 $s$ 是单棵树的"强度"(分类边距的期望),ρˉ\bar{\rho} 是树之间的平均相关性。这个式子的价值不在界紧不紧(它相当松),而在它把可调旋钮明确成了两个,并指出它们方向相反:减小 $m$(每节点候选特征数)会降低 ρˉ\bar{\rho},但同时也降低 $s$$m$ 的最优值就落在这两者的拉扯之间——这也是为什么 $m$ 是随机森林里唯一真正需要调的超参数。

袋外样本为什么恰好是 36.8%

"约 1/3 抽不到"这个说法不够精确,而精确值来得很漂亮。

Bootstrap 从 $n$ 个样本里有放回地抽 $n$ 次。对某个固定样本 $i$,单次没抽到它的概率是 $1 - 1/n$$n$ 次独立抽取都没抽到的概率就是

(11n)n n e10.367879\left(1 - \frac{1}{n}\right)^n \xrightarrow{\ n \to \infty\ } e^{-1} \approx 0.367879

$n$ 时它收敛得多快,值得列一下:

$n$251020501001000\infty
袋外比例0.2500.3280.3490.3590.3640.3660.36770.3679

这张表最该注意的是收敛速度:$n = 50$ 时已经是 0.364,与极限只差 1%。也就是说 36.8% 在任何实用规模上都成立,不需要"样本足够多"这个前提。

由此还得到一个常被引用的数:每棵树的 bootstrap 训练集里,不同样本约占 11/e63.2%1 - 1/e \approx 63.2\%——剩下的名额被重复抽中的样本占掉了。所以"bootstrap 样本和原数据一样大"只是数量上的说法;论信息量,它只见到约 63% 的个体。

袋外误差的可靠程度也能由此估出来:每个样本平均会成为约 $0.368B$ 棵树的袋外样本。$B = 500$ 时,每个样本的袋外预测由约 184 棵树投票产生——按上一节那张方差表,184 棵树早已贴住方差下限。这才是袋外误差能顶替验证集的真正理由:它不是"凑合的替代品",而是一个规模只小三分之一、性能几乎无差别的真实集成在留出数据上的误差。

袋外误差:免费的验证集

每棵树的 OOB 样本提供了一种无需额外验证集的误差估计:

OOB Error=1ni=1n1[y^iOOByi]\text{OOB Error} = \frac{1}{n} \sum_{i=1}^{n} \mathbf{1}\left[\hat{y}_i^{\text{OOB}} \neq y_i\right]

其中 y^iOOB\hat{y}_i^{\text{OOB}} 是所有没有在训练集中见过样本 $i$ 的树对其的预测平均。研究表明,OOB 误差是泛化误差的无偏估计,与用独立测试集估计的结果接近。

特征重要性

随机森林的一大工程优势是能够自然地估计每个特征的重要性:

基于 Gini 不纯度/信息增益:对每个特征,累计所有树中所有该特征参与分裂时带来的不纯度下降量。

基于 OOB 置换:对每个特征,将测试集中该特征的值随机打乱(破坏其与目标的关联),测量预测精度下降多少。下降越大,特征越重要。这种方法更鲁棒,但计算代价更高。

特征重要性的陷阱:高基数偏差

自带的特征重要性是随机森林最受欢迎的功能,也是最容易被误用的。

基于不纯度的重要性(Mean Decrease in Impurity, MDI)统计的是"该特征参与分裂时带来的不纯度下降总量"。问题出在候选切点的数量不平等:一个连续特征在 $n$ 个样本上有多达 $n-1$ 个可能切点,一个二值特征只有 1 个。切点多的特征更容易碰巧找到一个让训练集不纯度下降的位置,于是即便它与标签完全无关,也会累积出可观的重要性。

有个很干脆的验证做法:往数据里加一列纯随机数(与标签独立),再看它的重要性排名。在含有若干低基数特征的数据集上,这一列常常排到中上位置。scikit-learn 的官方文档为此明确警告:基于不纯度的重要性"对高基数特征有强偏好",而且它是在训练集上算的——只要模型有能力用某个特征去过拟合,这个特征的重要性就会很高,哪怕它对预测目标毫无用处。Strobl 等人在 2007 年(BMC Bioinformatics)系统刻画了这个问题:偏差同时来自候选切点数量与 bootstrap 采样,并给出了基于条件推断树的无偏替代方案。

工程上更常用的修正是置换重要性(Permutation Importance):把某一列的取值在留出集上随机打乱,测量模型精度下降多少。它有两个决定性优点——在留出集上算,所以"过拟合出来的重要性"会自动露馅;完全不看树结构,所以与候选切点的数量无关。代价是要重复多次前向预测,计算量高一个量级。

置换重要性也不是万能的,它有一个已知的失效模式:相关特征互相掩护。若两列几乎重复(例如身高的厘米值与米值),打乱其中一列,模型还能从另一列拿到同样的信息,于是两列的置换重要性都接近 0——结论会变成"这两个特征都不重要",而它们其实是同一个很重要的特征。

该记住的是:特征重要性回答的永远是"在这个已训好的模型里,这一列被用得有多狠",而不是"这个变量对结果有多大因果作用"。把它当因果证据用,是这个工具最常见的误用方式,在医学与社会科学的应用里代价尤其大。

现场:默认参数里藏着的一处分歧

上面说 $m$(每节点候选特征数)是随机森林唯一真正要调的超参数。有意思的是,主流实现在它的默认值上并不一致,而且分歧不小。

实现分类任务默认 $m$回归任务默认 $m$
R randomForestp\lfloor\sqrt{p}\rfloormax(p/3, 1)\max(\lfloor p/3\rfloor,\ 1)
scikit-learn(1.1 起)"sqrt",即 p\sqrt{p}1.0,即全部 $p$ 个特征

第二行右格是关键:scikit-learn 的 RandomForestRegressor 默认不做列随机。按前面的方差分析,这等于把 ρ\rho 放在最高档——它其实是纯 Bagging,不是布雷曼定义的那个随机森林。这个默认值在 1.1 版之前写作 "auto",含义相同,只是更隐蔽;社区为它专门开过 issue 讨论要不要改(scikit-learn #20111),最终选择了保留并把名字改得诚实一些。

实践含义很直接:用 scikit-learn 做回归时,max_features 应当显式设成 "sqrt"$1/3$,再与默认值做一次交叉验证对比。 这不是抠细节——在特征较多、且存在少数极强特征的数据上,这一个参数的差别可以大于换模型带来的差别。

顺带说一句身世:随机森林不是从零冒出来的。Amit 与 Geman 在 1997 年(Neural Computation)就提出在节点分裂时只搜索一个随机的候选决策子集;Ho 在 1998 年(IEEE TPAMI)提出随机子空间法(Random Subspace Method),让每棵树在随机选出的特征子空间里生长。布雷曼 2001 年的贡献是把 bootstrap 行随机与节点级列随机组合起来(注意与 Ho 的差别:Ho 是每棵树选一次特征子集,布雷曼是每个节点都重选一次),并给出前面那条强度-相关性误差界。"随机森林"这个名字属于布雷曼,但它的两层随机性各有出处。

与梯度提升的对比

维度随机森林梯度提升(XGBoost 等)
树的关系并行、独立串行、相互依赖
训练速度快(可并行)较慢
调参难度低(树多就行)高(学习率、深度等敏感)
偏差-方差低方差,偏差略高更低偏差,方差可控
在表格数据上的性能很强通常更强(竞赛常胜者)

随机森林在工业中的地位

在深度学习流行之前,随机森林是大多数机器学习竞赛和工业应用的首选。即使在深度学习时代,随机森林在以下场景仍是首选:

医疗诊断与临床决策:医生需要理解"为什么"模型做出某个预测,随机森林的特征重要性提供了可靠的解释依据,且不像神经网络那样需要大量标注数据。

金融信用评分:监管要求金融机构能解释拒绝贷款的原因,随机森林比深度网络更容易满足这一合规需求。

特征工程指导:随机森林的特征重要性分析常用于"探索性数据分析(EDA)"阶段,帮助数据科学家决定哪些特征值得深入挖掘或工程化。

Scikit-learn 中的一行代码

python
from sklearn.ensemble import RandomForestClassifier
rf = RandomForestClassifier(n_estimators=500, n_jobs=-1)
rf.fit(X_train, y_train)
```

这是机器学习实践中"首先尝试的基线模型"之一——不需要特征缩放,处理缺失值,几乎不需要调参就有不错的结果。

代价与争议

可解释性丧失:单棵决策树可以可视化和追踪,随机森林则是"黑盒"。特征重要性只告诉"哪些特征重要",不告诉"如何使用"。

内存消耗:存储数百棵完整决策树需要大量内存,对超大数据集是挑战。

不适合稀疏数据:在高维稀疏数据(如文本的词袋特征)上,随机森林不如线性模型(SVM、逻辑回归)有效,因为特征随机性导致很少有意义的分裂被发现。

理论基础:布雷曼(2001)证明了随机森林在树数量趋无穷时不会过拟合,但对其泛化误差的精确界定仍不完整。实践经验长期领先于理论理解。

跨域连接

  • 概率论:多数票的错误率就是二项分布的上尾,只要单个投票者的正确率过半,人数越多集体越准。这条式子与孔多塞的陪审团定理完全相同——随机森林等于把一条十八世纪的政治算术实现成了算法,前提也照搬过来了:投票者必须相互独立。
  • 统计学:而真实的树并不独立,于是平均值的方差有一个不随数量下降的地板,由两两相关系数决定。同一条式子在聚类抽样的设计效应、重复测量的组内相关、元分析的随机效应模型里反复出现:凡是平均一堆不独立的东西,都逃不掉那个地板。
  • 决策树:单棵树方差高、对数据扰动极敏感,这正是被平均的前提。列随机让每棵树单独变弱,却把相关性压下来——净效果为正,因为地板降得比单棵树的方差升得多。两层随机各司其职,不是同一件事做两遍。
  • 因果推断的可信性革命:特征重要性回答的是"这一列在这个已训好的模型里被用得多狠",不是"这个变量对结果有多大因果作用"。基于分裂的重要性还偏向取值多的特征,且是在训练集上算的;把它当因果证据用,在医学与社会科学里代价最大。
  • 气候模拟:集合预报同样靠平均多个成员来压不确定性,也同样撞上那个地板:共享同一套物理假设与参数化方案的模式,误差高度相关,加成员数的收益很快见底。多样性而非数量,才是决定集合价值的量。

参考文献

  • Breiman, L. Random Forests. Machine Learning 45(1), 5–32 (2001).(两层随机性、袋外估计与 PEρˉ(1s2)/s2PE^* \leq \bar{\rho}(1-s^2)/s^2 的强度-相关性上界)
  • Breiman, L. Bagging Predictors. Machine Learning 24(2), 123–140 (1996).
  • Ho, T. K. The Random Subspace Method for Constructing Decision Forests. IEEE TPAMI 20(8), 832–844 (1998).
  • Amit, Y. & Geman, D. Shape Quantization and Recognition with Randomized Trees. Neural Computation 9(7), 1545–1588 (1997).
  • Strobl, C. et al. Bias in Random Forest Variable Importance Measures: Illustrations, Sources and a Solution. BMC Bioinformatics 8, 25 (2007).
  • Hastie, T., Tibshirani, R. & Friedman, J. The Elements of Statistical Learning. 2nd ed., Springer, 2009.(第 15 章给出相关性方差分解 ρσ2+(1ρ)σ2/B\rho\sigma^2 + (1-\rho)\sigma^2/B
  • Pedregosa, F. et al. Scikit-learn: Machine Learning in Python. JMLR 12, 2825–2830 (2011).(max_features 默认值与不纯度重要性偏差的警告见其在线文档)

延伸阅读

  • Biau, G. & Scornet, E. A Random Forest Guided Tour. TEST 25(2), 197–227 (2016).
  • Molnar, C. Interpretable Machine Learning. 2nd ed., 2022.(特征重要性偏差、置换重要性与相关特征互相掩护的实践讨论)