EH's Blog

随机森林(Random Forest)#

上一篇学了决策树:它能画成一棵”不断问问题”的树,可解释性很强。但它有个大毛病——容易过拟合、还不稳定(训练数据稍微变一点,整棵树就大变样)。

随机森林就是专门治这个毛病的:种很多棵决策树,让它们”投票”做决定。这就是最经典的集成学习(Ensemble Learning)方法之一。


一、为什么要”一堆树”而不是”一棵树”?#

先看一个朴素的道理:

三个臭皮匠,顶个诸葛亮。

  • 一个专家(单棵决策树)可能判断失误
  • 但如果问很多个独立的专家,然后少数服从多数,整体就靠谱得多

这就是集成学习的核心思想:把多个弱模型组合成一个强模型。

决策树的缺点(随机森林要解决的)#

回忆上一篇,单棵决策树有两个毛病:

缺点表现
容易过拟合深度设得大时,把训练集”背”下来,新数据表现差
不稳定训练数据稍微变一点,树的结构可能完全不同,预测结果波动大

随机森林的解决思路:种很多棵树,每棵树都”不一样”,让它们的错误互相抵消。


二、随机森林的两个”随机”#

名字里的”随机”就藏在这里。每棵树的训练都不是用全部数据,而是做了两次随机:

随机 1:样本抽样(Bagging)#

对每棵树,从原始数据里”有放回”地随机抽一部分样本(专业词叫 Bootstrap 自助采样)。

“有放回”什么意思?抽到一个样本记录后,把它放回去再抽,所以同一个样本可能被抽到多次,也可能一次都没被抽到。

比如打球数据集有 14 条记录,每棵树:

原始 14 条: D1 D2 D3 D4 D5 D6 D7 D8 D9 D10 D11 D12 D13 D14
                ↓ 有放回随机抽 14 次
第 1 棵树:   D1 D1 D4 D2 D8 D3 D1 D9 D5 D6 D7 D9 D14 D2   (有的重复,有的缺失)
第 2 棵树:   D5 D8 D2 D9 D1 D3 D6 D1 D7 D4 D9 D10 D12 D1
第 3 棵树:   ...
plaintext

每棵树的训练数据都不一样,这就是”袋装”(Bagging = Bootstrap + Aggregating)。

随机 2:特征随机选择#

每棵树的每个节点在选划分特征时,不是看全部特征,而是从所有特征里随机挑一部分(比如 m\sqrt{m} 个),再从中选最优的。

目的:让树与树之间尽量不相关。如果每棵树都用同样的特征,那它们会”长得差不多”,投票就失去意义了。


三、随机森林的构建流程(手把手)#

造一棵”森林”就四步:

  1. 确定要种多少棵树 TT(比如 100 棵)
  2. 对每棵树 tt:
    • 从原始数据有放回地抽样本(Bootstrap)→ 得到该树的训练集
    • 用这些样本建一棵决策树,但每个节点划分时随机挑一部分特征再选最优
    • 不剪枝,让它长到足够深(随机森林靠”随机”防过拟合,不靠剪枝)
  3. 重复第 2 步 TT 次,得到 TT 棵互不相同的树
  4. 预测时:
    • 分类:TT 棵树各自投票,票数最多的类别胜出
    • 回归:TT 棵树各自给出数值,取平均值作为结果

用打球数据示意(假设 3 棵树):

        新样本(今天:晴、风大)
              ↓
  树1: 不去   树2: 去   树3: 不去
              ↓ 投票(少数服从多数)
        结果:不去
plaintext

四、为什么”随机”能让它更好?#

4.1 降低方差(更稳定)#

单棵决策树方差大(不稳定)。如果造 nn 棵独立同分布的树,每棵的方差是 σ2\sigma^2,那么平均之后方差会缩小:

Var(1n∑i=1nXi)=σ2nVar\left(\frac{1}{n}\sum_{i=1}^{n}X_i\right) = \frac{\sigma^2}{n}

树越多,波动越小,结果越稳定。

4.2 特征随机让树”不相关”#

如果所有树都用相同的特征,它们相关性高,上面的方差公式就不成立了(因为 XiX_i 之间相关)。

随机挑特征 → 树之间尽量独立 → 方差真正降下来 → 更抗过拟合。

一句话:“随机”制造了多样性,多样性带来了稳定性。


五、两个重要补充概念#

5.1 OOB(袋外样本)#

因为有放回抽样,每棵树的训练集没用到的数据(约 37% 的样本)叫做袋外样本(Out-Of-Bag)。

这些样本没参与训练,正好可以当”免费验证集”:

用 OOB 样本测试这棵树 → 得到袋外误差,无需另外划分验证集就能评估模型好坏。这是随机森林的隐藏福利。

5.2 特征重要性#

随机森林还能告诉我们哪个特征更重要(通常用”某个特征被随机打乱后,预测误差上升多少”来衡量)。这对特征筛选很有用。


六、优缺点#

优点:

  • 抗过拟合:比单棵决策树稳得多
  • 对数据扰动不敏感:很鲁棒
  • 能处理高维数据、无需特征缩放
  • 自带 OOB 误差评估、能算特征重要性
  • 分类、回归通吃,几乎不用调参就能有不错效果

缺点:

  • 可解释性下降:几百棵树没法像单棵树那样画出来讲给人听
  • 训练和预测比单棵树慢(要建很多树)
  • 对噪声大的数据也可能过拟合
  • 模型偏大,占用内存

七、Python 代码:和决策树对比#

复用上一篇的”打球数据集”和”房价数据集”,直观对比一棵树 vs 森林:

import numpy as np
from sklearn.ensemble import RandomForestClassifier, RandomForestRegressor
from sklearn.tree import DecisionTreeClassifier, DecisionTreeRegressor

# ---------- 分类:打球数据集(同上一篇) ----------
X = np.array([
    [0,0,0,0],[0,0,0,1],[1,0,0,0],[2,1,0,0],[2,2,1,0],[2,2,1,1],
    [1,2,1,1],[0,1,0,0],[0,2,1,0],[2,1,1,0],[0,1,1,1],[1,0,0,1],
    [1,0,1,0],[2,1,0,1],
])
y = np.array([0,0,1,1,1,0,1,0,1,1,1,1,1,0])

# 单棵树 vs 随机森林
tree = DecisionTreeClassifier(random_state=0)
forest = RandomForestClassifier(n_estimators=100, random_state=0)
tree.fit(X, y)
forest.fit(X, y)
print("单棵树训练集准确率:", tree.score(X, y))
print("随机森林训练集准确率:", forest.score(X, y))

# 特征重要性(随机森林的隐藏福利)
print("特征重要性:", forest.feature_importances_)

# ---------- 回归:房价 ----------
Xh = np.array([[40],[50],[60],[80],[90],[100]])
yh = np.array([80,90,110,200,220,250])

reg_tree = DecisionTreeRegressor(random_state=0)
reg_forest = RandomForestRegressor(n_estimators=100, random_state=0)
reg_tree.fit(Xh, yh)
reg_forest.fit(Xh, yh)
print("单棵树预测 70m²:", reg_tree.predict([[70]]))
print("随机森林预测 70m²:", reg_forest.predict([[70]]))
python

注意:数据量小的时候,随机森林的优势不明显(数据多、特征多时优势才大)。


八、总结#

一句话记住随机森林:

随机森林 = 种很多棵”用随机样本、随机特征”长出来的决策树,分类靠投票、回归靠平均,用”人多力量大”换来稳定和抗过拟合。

它是机器学习里最常用、最好上手的集成方法之一。理解了它,再学 GBDT、XGBoost 就有基础了——那些是另一条路线(“串行”地一棵棵补错),而不是”并行”地投票。

随机森林
https://ehnotgod.site/zh/blog/%E9%9A%8F%E6%9C%BA%E6%A3%AE%E6%9E%97
Author EH
Published at August 9, 2026