Day 8:随机森林原理与实践
Day 8随机森林原理与实践 目录集成学习概述Bagging原理随机森林核心机制OOB评估特征重要性随机森林 vs 决策树超参数调优第一部分集成学习概述1.5小时理论1.1 什么是集成学习定义集成学习通过构建并结合多个学习器来完成学习任务通常获得比单一学习器更显著的泛化性能。核心思想三个臭皮匠顶个诸葛亮1.2 集成学习分类类型代表算法特点并行/串行Bagging随机森林并行训练降低方差并行BoostingAdaBoost, XGBoost串行训练降低偏差串行Stacking多层模型用元学习器组合并行串行1.3 为什么集成有效数学原理假设有nnn个独立分类器每个准确率为p0.5p 0.5p0.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 AggregatingBootstrap自助采样有放回地采样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_sampleslen(X)indicesnp.random.choice(n_samples,n_samples,replaceTrue)returnX[indices],y[indices],indices随机抽样函数用于从给定的一维数组或整数范围中随机抽取元素。numpy.random.choice(a,sizeNone,replaceTrue,pNone)参数说明: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相同且所有概率之和必须为 12.3 Bagging算法流程输入训练集D(x1,y1),⋯ ,(xm,ym)D {(x_1,y_1), \cdots, (x_m,y_m)}D(x1,y1),⋯,(xm,ym)基学习算法LLL训练轮数TTT过程fort1t 1t1toTTT:DtD_tDt Bootstrap(DDD) # 自助采样htL(Dt)h_t L(D_t)htL(Dt)# 训练基学习器end输出H(x)argmaxy∈Y∑t1TI(ht(x)y)H(x) \text{argmax}_{y∈Y} \sum_{t1}^{T} \text{I}(h_t(x)y)H(x)argmaxy∈Y∑t1TI(ht(x)y)# 投票2.4 Bagging的方差降低单棵决策树Var(h)σ2 \text{Var}(h) \sigma^2Var(h)σ2Bagging后的方差假设独立Var(H)σ2T \text{Var}(H) \cfrac{\sigma^2}{T}Var(H)Tσ2实际中基学习器不完全独立但仍能显著降低方差。第三部分随机森林核心机制3.1 随机森林的两大随机性随机性说明作用样本随机Bootstrap采样增加数据多样性特征随机每次分裂随机选择特征子集增加模型多样性3.2 特征随机选择过程假设总特征数为nnn每次分裂时随机选择kkk个特征从这kkk个特征中选择最佳分裂特征常用kkk值分类knk \sqrt{n}kn回归kn/3k n/3kn/3作用减少特征间的相关性防止强特征主导所有树提高模型的多样性3.3 随机森林算法流程输入训练集DDD树的数量TTT特征子集大小kkk过程fort1t 1t1toTTT:DtBootstrap(D)D_t \text{Bootstrap}(D)DtBootstrap(D) 构建决策树hth_tht: while 未达到停止条件: 从所有特征中随机选择kkk个特征 从这kkk个特征中选择最佳分裂 分裂节点 endend输出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 什么是OOBOOBOut-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 rfRandomForestClassifier(n_estimators100,oob_scoreTrue)rf.fit(X_train,y_train)print(fOOB 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 特征重要性的解读importancesrf.feature_importances_ feature_importance_dfpd.DataFrame({feature:feature_names,importance:importances}).sort_values(importance,ascendingFalse)重要性的含义高重要性该特征对预测贡献大低重要性该特征贡献小可考虑删除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通常保持True7.2 调优顺序n_estimators: 先固定一个较大值观察OOB误差max_depth: 限制深度防止过拟合min_samples_split/min_samples_leaf: 进一步正则化max_features: 微调特征随机性7.3 学习曲线分析# 不同树数量的OOB误差oob_scores[]forninrange(10,201,10):rfRandomForestClassifier(n_estimatorsn,oob_scoreTrue,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()