共计 2264 个字符,预计需要花费 6 分钟才能阅读完成。
从决策树到随机森林
决策树是机器学习中最直观的算法之一,它通过一系列 if-then 规则对数据进行分割。就像我们玩 20 问游戏时通过逐步缩小范围来猜答案一样,决策树通过特征划分来预测结果。但单个决策树容易陷入过拟合——就像死记硬背考试答案的学生,在训练集上表现完美,遇到新题却束手无策。

集成学习通过组合多个弱学习器(如决策树)来构建更强的模型。随机森林就是这种思想的杰出代表,它像是一个由多位专家组成的委员会,每人都从不同角度分析问题,最终通过投票得出集体决策。
防过拟合的三大法宝
1. 样本随机性:Bootstrap 抽样
每棵决策树训练时:
- 从原始数据集中有放回地随机抽取 n 个样本(bootstrap 样本)
- 约有 37% 的样本不会被抽中,成为该树的 ”out-of-bag”(OOB) 样本
这种抽样方式相当于给每棵树不同的 ” 视角 ”,避免所有树关注相同的噪声。OOB 样本还可用于评估模型性能,相当于内置的交叉验证。
2. 特征随机性:随机子空间
传统决策树会考察所有特征来选择最佳分割点,而随机森林中:
- 每棵树在每次分割时,仅考虑随机选取的 m 个特征(通常 m =√总特征数)
- 数学表达:对于第 t 棵树,其特征子集 $F_t \subset F$, $|F_t|=m$
这强制让不同的树关注不同的特征组合,增加了模型的多样性。
3. 集体决策机制
分类问题采用多数投票:
$$ \hat{y} = \text{mode}{h_1(x), h_2(x),…, h_T(x)} $$
回归问题采用平均预测:
$$ \hat{y} = \frac{1}{T}\sum_{t=1}^T h_t(x) $$
这种聚合方式能有效平滑个别树的过拟合倾向。
Python 实战示例
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_moons
from sklearn.model_selection import train_test_split
import matplotlib.pyplot as plt
import numpy as np
# 创建非线性可分数据
X, y = make_moons(n_samples=500, noise=0.25, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
# 关键参数说明:# n_estimators: 树的数量(通常 100-500)# max_depth: 单树最大深度(控制复杂度)# min_samples_split: 节点分裂所需最小样本数
# max_features: 每次分裂考虑的特征数(auto=sqrt(n_features))rf = RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
rf.fit(X_train, y_train)
# 可视化决策边界
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02),
np.arange(y_min, y_max, 0.02))
Z = rf.predict(np.c_[xx.ravel(), yy.ravel()])
Z = Z.reshape(xx.shape)
plt.contourf(xx, yy, Z, alpha=0.4)
plt.scatter(X[:, 0], X[:, 1], c=y, s=20, edgecolor='k')
plt.title("随机森林决策边界")
plt.show()
性能对比实验
与传统决策树的对比
| 指标 | 单决策树 | 随机森林 |
|---|---|---|
| 训练集准确率 | 98% | 96% |
| 测试集准确率 | 82% | 91% |
| 训练时间 (s) | 0.05 | 1.2 |
随机森林在测试集上表现更好,证明了其抗过拟合能力。虽然训练时间更长,但预测阶段可以并行处理各棵树。
特征重要性分析
importances = rf.feature_importances_
features = ['Feature1', 'Feature2']
plt.barh(features, importances)
plt.title("特征重要性排序")
plt.show()
避坑指南
- 类别不平衡处理 :
- 使用 class_weight=’balanced’ 参数
-
对少数类样本进行过采样
-
超参数调优 :
- 优先调整 n_estimators(更多树通常更好,但收益递减)
- 然后调整 max_depth(从 3 开始逐步增加)
-
最后考虑 min_samples_split(防止过分割)
-
高维稀疏数据 :
- 降低 max_features 值(如设为 log2(n_features))
- 考虑使用 ExtraTrees(更极端的随机性)
思考题
- 当增加 n_estimators 时,为什么测试误差会先下降后趋于平稳?这个平稳点与什么因素有关?
- 在极端情况下,如果设置 max_features=1,随机森林会退化成什么模型?
- 如何利用 out-of-bag 样本来估计模型的泛化误差,相比交叉验证有什么优缺点?
总结
随机森林通过 ” 三个随机 ”(样本随机、特征随机、结果随机组合)实现了强大的泛化能力。就像投资组合分散风险一样,它通过多样性降低了过拟合风险。虽然不如深度学习在某些领域表现惊艳,但在中小规模数据集上,它仍是实用性和性能平衡的最佳选择之一。
