Day 8:随机森林原理与实践
Day 8:随机森林原理与实践
📋 目录
- 集成学习概述
- Bagging原理
- 随机森林核心机制
- OOB评估
- 特征重要性
- 随机森林 vs 决策树
- 超参数调优
第一部分:集成学习概述(1.5小时理论)
1.1 什么是集成学习?
定义:集成学习通过构建并结合多个学习器来完成学习任务,通常获得比单一学习器更显著的泛化性能。
核心思想:三个臭皮匠,顶个诸葛亮
1.2 集成学习分类
| 类型 | 代表算法 | 特点 | 并行/串行 |
|---|---|---|---|
| Bagging | 随机森林 | 并行训练,降低方差 | 并行 |
| Boosting | AdaBoost, XGBoost | 串行训练,降低偏差 | 串行 |
| Stacking | 多层模型 | 用元学习器组合 | 并行+串行 |
1.3 为什么集成有效?
数学原理:
假设有nnn个独立分类器,每个准确率为p>0.5p > 0.5p>0.5,通过投票集成的准确率为:
P(正确)=∑k=⌊n/2⌋+1n(nk)pk(1−p)n−k P(\text{正确}) = \sum_{k=\lfloor n/2 \rfloor + 1}^{n} \binom{n}{k} p^k (1 - p)^{n - k}P(正确)=k=⌊n/2⌋+1∑n(kn)pk(1−p)n−k
随着nnn增加,准确率趋近于1。
三种情况:
- 准确性:基学习器优于随机猜测
- 多样性:基学习器之间有差异
- 独立性:基学习器错误不相关
第二部分:Bagging原理
2.1 Bagging定义
Bagging = Bootstrap + Aggregating
- Bootstrap:自助采样,有放回地采样
- Aggregating:聚合多个模型的预测
2.2 Bootstrap采样
采样过程:
从原始数据集DDD中随机抽取mmm个样本(有放回),得到子集DiD_iDi
数学性质:
- 每个样本被选中的概率:1−(1−1/m)m≈1−1/e≈63.2%1 - (1 - 1/m)^m \approx 1 - 1/e \approx 63.2\%1−(1−1/m)m≈1−1/e≈63.2%
- 约36.8%的样本不会被选中(袋外样本)
# Bootstrap采样示例importnumpyasnpdefbootstrap_sample(X,y):n_samples=len(X)indices=np.random.choice(n_samples,n_samples,replace=True)returnX[indices],y[indices],indices随机抽样函数,用于从给定的一维数组或整数范围中随机抽取元素。
numpy.random.choice(a,size=None,replace=True,p=None)参数说明:
a- 候选项
- 类型:一维数组(如
np.array([0,1,2])或[0,1,2])或整数- 说明:
- 如果是数组/列表:从该序列中随机抽取元素
- 如果是整数
N:等价于np.arange(N),即从[0, 1, ..., N-1]中抽取
size(可选) - 输出形状
- 类型:整数或元组(如
(m, n, k))- 默认值:
None(返回单个元素)- 说明:决定输出数组的形状。如果给定
(m, n, k),则抽取m × n × k个元素
replace(可选) - 是否放回抽样
- 类型:布尔值
- 默认值:
True(有放回抽样)- 说明:
True:每次抽取后元素放回,允许重复False:无放回抽样,每个元素只能被选中一次
p(可选) - 概率分布
- 类型:一维数组
- 默认值:
None(等概率抽取)- 说明:指定每个元素被抽取的概率,数组长度必须与
a相同,且所有概率之和必须为 1
2.3 Bagging算法流程
输入:训练集D=(x1,y1),⋯ ,(xm,ym)D = {(x_1,y_1), \cdots, (x_m,y_m)}D=(x1,y1),⋯,(xm,ym)
基学习算法LLL
训练轮数TTT
过程:
- fort=1t = 1t=1toTTT:
- DtD_tDt= Bootstrap(DDD) # 自助采样
- ht=L(Dt)h_t = L(D_t)ht=L(Dt)# 训练基学习器
- end
输出:H(x)=argmaxy∈Y∑t=1TI(ht(x)=y)H(x) = \text{argmax}_{y∈Y} \sum_{t=1}^{T} \text{I}(h_t(x)=y)H(x)=argmaxy∈Y∑t=1TI(ht(x)=y)# 投票
2.4 Bagging的方差降低
单棵决策树:
Var(h)=σ2 \text{Var}(h) = \sigma^2Var(h)=σ2
Bagging后的方差(假设独立):
Var(H)=σ2T \text{Var}(H) = \cfrac{\sigma^2}{T}Var(H)=Tσ2
实际中基学习器不完全独立,但仍能显著降低方差。
第三部分:随机森林核心机制
3.1 随机森林的两大随机性
| 随机性 | 说明 | 作用 |
|---|---|---|
| 样本随机 | Bootstrap采样 | 增加数据多样性 |
| 特征随机 | 每次分裂随机选择特征子集 | 增加模型多样性 |
3.2 特征随机选择
过程:
- 假设总特征数为nnn
- 每次分裂时,随机选择kkk个特征
- 从这kkk个特征中选择最佳分裂特征
常用kkk值:
- 分类:k=nk = \sqrt{n}k=n
- 回归:k=n/3k = n/3k=n/3
作用:
- 减少特征间的相关性
- 防止强特征主导所有树
- 提高模型的多样性
3.3 随机森林算法流程
输入:训练集DDD,树的数量TTT,特征子集大小kkk
过程:
- fort=1t = 1t=1toTTT:
- Dt=Bootstrap(D)D_t = \text{Bootstrap}(D)Dt=Bootstrap(D)
- 构建决策树hth_tht:
- while 未达到停止条件:
- 从所有特征中随机选择kkk个特征
- 从这kkk个特征中选择最佳分裂
- 分裂节点
- end
- end
输出:H(x)=majority_vote(ht(x))H(x) = \text{majority\_vote}({h_t(x)})H(x)=majority_vote(ht(x))
3.4 随机森林 vs Bagging决策树
| 对比项 | Bagging决策树 | 随机森林 |
|---|---|---|
| 样本随机 | ✅ | ✅ |
| 特征随机 | ❌ | ✅ |
| 树的相关性 | 较高 | 较低 |
| 泛化性能 | 好 | 更好 |
第四部分:OOB评估
4.1 什么是OOB?
OOB(Out-Of-Bag):在Bootstrap采样中,未被选中的样本(约36.8%)。
OOB样本的特点:
- 没有参与当前树的训练
- 可以作为验证集使用
4.2 OOB误差计算
算法流程:
对于每个样本(xi,yi)(x_i, y_i)(xi,yi):
1. 找出所有没有使用该样本训练的树 2. 用这些树对 $x_i$ 进行预测 3. 投票得到预测结果 4. 与真实标签比较计算误差最终OOB误差 = 所有样本的平均误差
4.3 OOB评估的优势
| 优势 | 说明 |
|---|---|
| 无需交叉验证 | 节省计算时间 |
| 无偏估计 | 样本未被用于训练 |
| 与Bagging一致 | 使用相同的数据分布 |
fromsklearn.ensembleimportRandomForestClassifier rf=RandomForestClassifier(n_estimators=100,oob_score=True)rf.fit(X_train,y_train)print(f"OOB Score:{rf.oob_score_:.4f}")4.4 OOB vs 交叉验证
| 对比项 | OOB | 交叉验证 |
|---|---|---|
| 计算成本 | 低(一次训练) | 高(多次训练) |
| 估计偏差 | 略乐观 | 无偏 |
| 适用场景 | 大规模数据 | 小规模数据 |
第五部分:特征重要性
5.1 特征重要性的两种计算方法
方法1:基于不纯度减少
原理:记录每个特征在所有树中减少的不纯度(基尼系数/熵)
计算步骤:
- 对于每棵树,记录每个节点分裂时的不纯度减少
- 将该减少量累加到对应特征上
- 对所有树取平均
- 归一化到0-1之间
方法2:基于OOB误差
原理:随机打乱特征值,观察OOB误差的变化
计算步骤:
- 计算原始OOB误差errbase\text{err}_{\text{base}}errbase
- 对特征jjj随机打乱,计算新OOB误差errperm\text{err}_{\text{perm}}errperm
- 重要性 =errperm−errbase\text{err}_{\text{perm}} - \text{err}_{\text{base}}errperm−errbase
- 差值越大,特征越重要
5.2 特征重要性的解读
importances=rf.feature_importances_ feature_importance_df=pd.DataFrame({'feature':feature_names,'importance':importances}).sort_values('importance',ascending=False)重要性的含义:
- 高重要性:该特征对预测贡献大
- 低重要性:该特征贡献小,可考虑删除
5.3 特征选择策略
| 策略 | 方法 | 适用场景 |
|---|---|---|
| 阈值筛选 | 删除重要性低于阈值的特征 | 快速筛选 |
| Top-K | 保留最重要的K个特征 | 固定维度 |
| 递归消除 | 逐步删除最不重要特征 | 精细选择 |
第六部分:随机森林 vs 决策树
6.1 性能对比
| 对比项 | 决策树 | 随机森林 |
|---|---|---|
| 过拟合风险 | 高 | 低 |
| 可解释性 | 强 | 弱 |
| 训练速度 | 快 | 慢 |
| 预测速度 | 快 | 慢 |
| 内存占用 | 小 | 大 |
| 特征重要性 | 有 | 有(更稳定) |
6.2 何时使用随机森林?
推荐使用:
- 数据量大,特征维度高
- 需要高预测精度
- 不要求强可解释性
- 存在过拟合风险
不推荐使用:
- 需要实时预测(延迟敏感)
- 资源受限(内存/计算)
- 需要明确的决策规则
- 数据量很小
第七部分:超参数调优
7.1 关键超参数
| 参数 | 含义 | 典型值 | 调优方向 |
|---|---|---|---|
n_estimators | 树的数量 | 100-500 | 越大越好,但有边际效应 |
max_depth | 最大深度 | 10-30 | 限制过拟合 |
min_samples_split | 分裂最小样本数 | 2-20 | 越大越保守 |
min_samples_leaf | 叶节点最小样本数 | 1-10 | 越大越平滑 |
max_features | 特征子集大小 | sqrt(n) | 控制多样性 |
bootstrap | 是否自助采样 | True | 通常保持True |
7.2 调优顺序
n_estimators: 先固定一个较大值,观察OOB误差max_depth: 限制深度,防止过拟合min_samples_split/min_samples_leaf: 进一步正则化max_features: 微调特征随机性
7.3 学习曲线分析
# 不同树数量的OOB误差oob_scores=[]forninrange(10,201,10):rf=RandomForestClassifier(n_estimators=n,oob_score=True,n_jobs=-1)rf.fit(X_train,y_train)oob_scores.append(rf.oob_score_)plt.plot(range(10,201,10),oob_scores)plt.xlabel('Number of Trees')plt.ylabel('OOB Score')plt.show()