先看效果:单棵决策树 vs 随机森林

左图是一棵决策树,右图是随机森林。注意左边决策边界的"锯齿"——那是过拟合的痕迹;右边的边界更平滑,泛化能力更强。 调整树的数量或深度,点击"重新训练"观察变化。

森林树的数量 20
树最大深度 5
森林树数 20 棵树投票
单树准确率 训练集
森林准确率 训练集
单棵决策树(容易过拟合)
随机森林(边界更平滑)

01 核心原理(大白话版)

你要决定要不要带伞,一个朋友说"不会下雨",你可能不放心。但如果你问了 100 个人,80 个说"会下雨",你会相信多数。

随机森林就是这样:训练很多棵各自略有不同的决策树,然后让它们投票。单棵树容易"走偏",但偏的方向各不相同,投票后偏差就互相抵消了。

为什么决策树需要"随机森林"?

决策树有一个严重缺点:方差太高。数据稍有变化,树的结构就可能完全不同。深树会把训练数据的每个细节都记住(过拟合),在新数据上表现很差。

核心思路:用多样性来换稳定性——每棵树都在稍微不同的数据和特征上训练,单棵树虽然不准,但它们的"错误"方向各不相同,投票后就准了。

两个关键的"随机"

1
Bootstrap 采样(行随机)

每棵树用的训练数据是有放回地随机抽取原始数据集的同等数量样本。大约 63% 的样本会被选到,36% 被遗漏(称为 OOB 样本,可用来估算泛化误差)。

2
特征随机采样(列随机)

每次寻找分裂点时,只从随机选出的 √p 个特征中挑最优(p 是总特征数)。这让每棵树不会全部被最强特征主导,增加树间多样性。

Bagging vs Boosting

随机森林(Bagging)

所有树并行独立训练,互不依赖。每棵树都是完整的深树,最后投票/取均值。目的是降低方差,防止过拟合。训练可以完全并行,速度快。

XGBoost(Boosting)

串行逐棵生长,每棵专门修正上一棵的错误。每棵树故意很浅(弱学习器)。目的是降低偏差,提高精度。需要顺序训练,且更容易过拟合。

预测时怎么投票?

1
分类任务:多数投票

每棵树给出自己的类别预测,取得票最多的类别作为最终结果。

2
回归任务:取平均

每棵树给出一个数值预测,最终结果是所有树预测值的平均。

一步步构建随机森林

第一步 Bootstrap 采样

有放回地从原始数据中抽取同等数量的样本,观察每次抽到的数据集有什么不同。

第二步 特征随机采样

每次分裂只考虑随机选出的部分特征,增加树间多样性,避免所有树都长得一样。

第三步 训练一棵随机树

把 Bootstrap 采样 + 特征随机采样合并进 CART 决策树,得到一棵"随机化"的树。

第四步 集成投票 + 观察准确率变化

训练 N 棵树,多数投票预测,观察准确率随树数量增加如何提升并趋于稳定。

02 代码

03 学术性讲解

偏差-方差分解

预测误差可以分解为三部分:

E[(y − f̂(x))²] = Bias²(f̂) + Var(f̂) + σ²

深决策树偏差低但方差高(记住训练数据的每个细节)。Bagging 通过对 B 棵树取平均,将方差降低为原来的 1/B(假设树间独立):

Var(f̄) = Var(fₜ) / B

实际中树间存在相关性(因为用同一份数据),特征随机采样降低树间相关性,使方差减少更接近理论值。

OOB 误差(Out-of-Bag Error)

每棵树的 Bootstrap 采样只用了约 63.2% 的数据,剩余 36.8% 称为袋外(OOB)样本。对每个训练样本,可以用那些没有用到它的树来预测它,得到无偏的泛化误差估计——不需要单独划分验证集:

OOB Error = (1/n) Σᵢ 𝟙[ŷᵢ_oob ≠ yᵢ]

特征重要性

随机森林天然提供特征重要性分数。最常用的是基尼重要性

Importance(j) = Σₜ Σₙ∈t [p(n) · ΔGini(n, j)]

对特征 j 的所有分裂节点,累加"分裂前后基尼系数的加权减少量"。另一种方法是排列重要性:随机打乱特征 j 的值,观察 OOB 误差增加了多少——增加越多说明该特征越重要。

树的数量 n_estimators

随机森林随着树数量增加,误差单调递减并趋于稳定——不会因为树太多而过拟合(与 Boosting 不同)。实践中通常 100-500 棵就足够,再多收益递减。

随机森林的树越多越好,但 XGBoost 的树太多会过拟合——这是 Bagging 和 Boosting 最重要的区别之一。

随机森林 vs XGBoost:如何选择?

优先考虑随机森林

数据量不大、特征少、需要快速出结果、对可解释性要求高、不想花时间调参时。OOB 误差自带验证,基本无需调参。

优先考虑 XGBoost

追求极致精度、数据量大、参加竞赛、有时间精调超参数时。通常在表格数据上比随机森林精度更高,但需要调 learning_rate、max_depth、n_estimators 等。