当前位置: 首页 > news >正文

ML:随机森林的基本原理与实现

在机器学习中,单棵决策树虽然直观、易解释,但它也有一个很明显的问题:对训练数据的微小变化往往比较敏感,容易长得过深,从而产生过拟合。随机森林(Random Forest)正是在这种背景下发展起来的重要方法。

一、随机森林的基本思想

随机森林的核心思想是:训练多棵彼此不同的决策树,并把它们的结果进行综合。

如果只训练一棵决策树,那么这棵树可能会过度依赖某些训练样本或某些特征,从而把训练集中的偶然波动也学进去。随机森林则尝试通过“多样化 + 集成”的方式缓解这个问题。

从直观上看,随机森林完成的是这样一件事:

• 不只看一棵树,而是同时训练很多棵树

• 每棵树都基于一个略有差异的数据视角进行学习

• 每棵树在分裂时也不会总是看到全部特征

• 最终分类时采用投票,回归时采用平均

图 1:随机森林的基本工作流程

Scikit-learn 对随机森林的描述正是:它是一种元估计器(meta estimator),会在数据的不同子样本上拟合多棵决策树,并通过平均来提升预测准确性、控制过拟合;分类场景对应 RandomForestClassifier,回归场景对应 RandomForestRegressor。

这说明,随机森林并不是在发明一种全新的“树结构”,而是在已有决策树基础上,通过集成策略提升整体性能。

二、随机森林为什么能比单棵树更稳

图 2:单棵决策树与随机森林的对比

1、单棵树的问题

单棵决策树的表达能力很强,但也正因为如此,它容易把训练集中的局部噪声和偶然模式学进去。这意味着:

• 单棵树往往方差较大

• 数据稍有变化,树结构就可能明显改变

• 预测结果容易不稳定

2、集成带来的稳定性

如果训练很多棵树,并让这些树尽可能“不要完全一样”,那么每棵树出错的方式就不会完全一致。

在这种情况下,把它们的结果综合起来,通常会产生两个重要效果:

• 分类中,多数投票可以削弱个别树的错误判断

• 回归中,平均值可以平滑个别树的波动输出

这就是随机森林比单棵树更稳健的根本原因。随机森林的核心就是用多棵带随机性的树来换取更好的泛化能力。

3、关键不只是“多”,而是“不同”

需要注意的是,随机森林成功的关键不只是树多,而是这些树要彼此存在差异。

如果所有树都看到完全相同的数据、总在每个节点上选择相同特征,那么它们最终会非常相似,集成的收益就会大幅下降。

因此,随机森林会通过两种主要机制来制造差异:

• 对训练样本做随机抽样

• 对候选特征做随机抽样

这两种随机性,正是“random forest”中“random”的来源。

三、随机森林中的两种随机机制

1、自助采样:让每棵树看到不同样本子集

随机森林通常对原始训练集进行有放回抽样,也就是 Bootstrap Sampling。这样,每棵树虽然都来自同一份原始数据,但它们实际看到的训练子集并不完全相同。

图 3:随机森林中的 Bootstrap 自助采样

Scikit-learn 的随机森林分类器(RandomForestClassifier)和随机森林回归器(RandomForestRegressor)默认都使用 bootstrap=True。

如果开启 bootstrap,每棵树所使用的样本子集大小还可以通过 max_samples 控制;若 bootstrap=False,则每棵树会使用整个数据集。

这意味着:不同树训练在不同样本分布上,树之间自然会产生差异,这种差异有助于降低整体方差。

2、特征子采样:让每次分裂都更随机

随机森林的第二种关键随机性,不是在整棵树层面,而是在每个节点分裂时体现出来。

图 4:随机森林中的特征随机子采样

具体来说,当树在某个节点寻找最佳划分特征时,它并不会总是看全部特征,而只会从一个随机抽取的特征子集中寻找最佳分裂。

这正是 max_features 参数控制的内容。Scikit-learn 当前默认设置中,分类器和回归器的 max_features 都是 "sqrt";也就是说,在每次分裂时,只考虑总特征数平方根数量级的随机特征子集。

这意味着:强势特征不会在所有树、所有节点上都一统天下,不同树会学到不同的特征组合与划分路径,集成结果会因此更加多样化。

四、随机森林的预测方式

1、分类:多数投票

在分类问题中,随机森林会让每棵树分别给出一个类别判断,然后以多数投票作为最终结果。

图 5:随机森林分类的多数投票机制

如果有 T 棵树,第 t 棵树对样本 x 的预测记为hₜ(x),那么最终类别可以理解为:

也就是说,哪一个类别获得的票数最多,就把样本判为哪一类。

2、回归:取平均值

在回归问题中,随机森林会让每棵树分别输出一个数值预测,再对这些预测值做平均:

这里:

• T 表示树的数量

• hₜ(x) 表示第 t 棵树的输出

• ŷ 表示最终预测值

图 6:随机森林回归的平均预测机制

这说明,随机森林在分类和回归中虽然输出形式不同,但核心思想是一致的:把多棵树的判断进行综合。

3、树的数量不是越少越好

随机森林中的 n_estimators 表示树的数量。Scikit-learn 当前默认值为 100。一般来说,树越多,结果越稳定,但训练与预测开销也会更大。

因此,n_estimators 并不是一个追求“越小越精简”的参数,而更像是在计算成本与稳定性之间做权衡。

五、随机森林的主要参数

1、n_estimators

n_estimators 表示森林中树的数量。

树的数量越多,模型通常越稳定,但训练和预测时间也会增加。Scikit-learn 当前默认值是 100。

2、max_features

max_features 表示每次分裂时可供选择的特征数。

它直接决定了树之间的差异程度,也是随机森林区别于普通 bagging 决策树的重要参数之一。当前默认值是 "sqrt"。

3、max_depth

max_depth 用于限制单棵树的最大深度。

如果不限制,树可能会长得很深,虽然单棵树拟合更强,但也更容易复杂化。随机森林虽然通过集成缓解了过拟合,但单棵树深度仍然值得控制。

4、min_samples_splitmin_samples_leaf

这两个参数分别控制:

• 一个内部节点至少有多少样本才允许继续分裂

• 一个叶节点至少保留多少样本

它们都是调节单棵树复杂度的重要手段。

5、bootstrapmax_samples

bootstrap 决定是否使用自助采样;默认值为 True。

max_samples 则在 bootstrap=True 时控制每棵树实际抽取多少样本。

这些参数共同决定了随机森林在“树的数量、树的复杂度、树之间差异性”三个方面的整体行为。

六、模型结果如何解释

1、比单棵树弱一些,但仍有一定解释性

随机森林的一个重要特点是:它通常比单棵决策树预测更稳,但可解释性会有所下降。

原因很简单:单棵树可以直接画出来,而随机森林由很多棵树组成,不再容易用一条清晰规则概括整体行为。

2、特征重要性

尽管整体规则难以完全展开,随机森林仍常通过特征重要性来给出一定程度的解释。

图 7:随机森林中的特征重要性

Scikit-learn 的树模型示例中,随机森林训练后可以通过 feature_importances_ 查看基于树分裂贡献的特征重要性。

这意味着,我们通常可以回答:

• 哪些特征对模型更重要

• 哪些特征几乎没有贡献

但需要注意的是,这种重要性并不等同于因果关系,也不应被过度解释。

3、局部解释与整体解释

从整体上看,随机森林不像线性回归那样能给出一组统一系数,也不像单棵树那样能给出一条清晰路径规则。

它更适合用来回答:

• 哪些特征总体上更有用

• 模型预测整体上依赖哪些变量

而不太适合直接给出一条“全局公式”。

七、Python 实现:随机森林分类示例

下面用鸢尾花数据集演示随机森林分类的基本实现方式。

RandomForestClassifier 用于分类任务。每棵树使用最佳分裂策略,相当于底层 DecisionTreeClassifier(splitter="best"),但通过样本与特征随机性形成整体集成。

from sklearn.datasets import load_iris # 加载鸢尾花数据集from sklearn.ensemble import RandomForestClassifier # 随机森林分类器(集成学习)from sklearn.model_selection import train_test_split # 数据集划分 # 1. 加载数据iris = load_iris()X = iris.data # 特征 (150,4)y = iris.target # 标签 (150,) # 2. 划分训练集与测试集(测试集20%,固定随机种子)X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42) # 3. 创建随机森林分类器model = RandomForestClassifier( n_estimators=100, # 决策树数量(集成100棵子树) max_depth=4, # 每棵树最大深度(限制复杂度) random_state=42 # 固定随机种子,保证可复现) # 4. 训练模型(Bagging集成:每棵树用不同自助样本训练)model.fit(X_train, y_train) # 5. 预测(所有树投票决定最终类别)y_pred = model.predict(X_test) print("前 10 个预测结果:", y_pred[:10])print("测试集得分:", model.score(X_test, y_test)) # 平均准确率print("特征重要性:", model.feature_importances_) # 各特征对分类的贡献度(总和为1)

这段代码展示了随机森林分类的基本工作流:

1、生成或加载数据

2、划分训练集与测试集

3、创建分类器

4、用 fit 训练森林

5、用 predict 输出类别

6、用 feature_importances_ 查看特征重要性

这里的 score() 对分类器默认返回准确率。

八、Python 实现:随机森林回归示例

下面再给出一个回归示例,说明随机森林如何通过多棵回归树的平均来完成连续数值预测。

RandomForestRegressor 的基本思想与分类器相同,只是最终输出由多数投票改为平均值。

from sklearn.datasets import make_regression # 生成回归数据集from sklearn.ensemble import RandomForestRegressor # 随机森林回归器from sklearn.model_selection import train_test_split # 数据集划分 # 1. 生成回归数据X, y = make_regression( n_samples=200, # 200个样本 n_features=5, # 5个特征 n_informative=5, # 全部特征有效(无冗余) noise=20, # 添加噪声,标准差20 random_state=42) # 2. 划分训练集与测试集(测试集20%)X_train, X_test, y_train, y_test = train_test_split( X, y, test_size=0.2, random_state=42) # 3. 创建随机森林回归器model = RandomForestRegressor( n_estimators=100, # 100棵决策树 max_depth=6, # 每棵树最大深度 random_state=42) # 4. 训练模型(所有树结果取平均作为最终预测)model.fit(X_train, y_train) # 5. 预测y_pred = model.predict(X_test) print("前 5 个真实值:", y_test[:5])print("前 5 个预测值:", y_pred[:5])print("测试集得分:", model.score(X_test, y_test)) # R²决定系数(越接近1越好)print("特征重要性:", model.feature_importances_) # 各特征贡献度(总和为1)

这段代码说明,随机森林回归并不是拟合一个单一公式,而是通过多棵回归树分别给出预测,再把这些结果平均起来。

九、随机森林的适用场景与主要局限

图 8:随机森林的适用场景与主要局限

1、适用场景

随机森林较适合以下情况:

• 可以是分类任务,也可以是回归任务

• 特征与目标之间可能存在非线性关系

• 希望模型比单棵树更稳健

• 不想做过多复杂特征工程

• 需要一个强力而通用的基线模型

在很多实际任务中,随机森林都是非常常见的首选基线之一。

2、主要局限

随机森林虽然强大,但也并不是万能方法。

(1)可解释性弱于单棵树:整体决策逻辑更难完整展开。

(2)模型体积和计算开销更大:树多时训练和预测都更重。

(3)对非常高维稀疏数据不一定最优:在某些文本等任务中,线性模型可能更合适。

(4)特征重要性不等于因果关系:解释时需要谨慎。

(5)仍需调参:树数、深度、特征采样比例等都会影响结果。

因此,随机森林更像是一种“稳健、强力、通用”的集成树模型,而不是任何情况下都绝对最优的终极方案。

📘 小结

随机森林通过“样本随机抽样 + 特征随机抽样 + 多树集成”的方式,提升了决策树的稳定性与泛化能力。它是理解 bagging、集成学习与树模型增强的重要入口。

“点赞有美意,赞赏是鼓励”

http://www.jsqmd.com/news/768633/

相关文章:

  • 沈阳建筑大学考研辅导班机构推荐:排行榜单与哪家好评测 - michalwang
  • Arm Cortex-R82寄存器架构与定时器控制详解
  • 【高级网络】虚拟化与云计算 (Virtualization Cloud) 深度解析
  • astral-sh发布的musl和gnu版本standalone python 性能比较
  • 用一颗6脚5050RGB灯珠,我复刻了同事那个超省资源的跑马灯+呼吸灯方案
  • 蓝桥杯单片机CT107D平台:用PCF8591的DAC做个简易数字电压表(附完整代码)
  • Spring学习(六)
  • 基于Alexa与Node.js的智能DNS查询技能开发实战
  • 西南林业大学考研辅导班机构推荐:排行榜单与哪家好评测 - michalwang
  • 别再死磕手册了!Xilinx 7系列FPGA配置模式选型指南(SPI/BPI/SelectMAP/JTAG)
  • AI 算法盒子国内外主流厂商全景盘点(2026)
  • 写论文软件哪个好?2026 实测:虎贲等考 AI 凭真文献 + 全流程 + 强合规,成毕业论文首选
  • 河南师范大学考研辅导班机构推荐:排行榜单与哪家好评测 - michalwang
  • Gitee统一SCA解决方案:重新定义开源治理新范式
  • 系统右键菜单集成Cursor编辑器:一键直达提升开发效率
  • 从“解决”到“消解”:电车难题作为AI元人文的第一次工程实验
  • C++模板技术(泛型编程)
  • 基于Next.js与多模型支持的私有化AI聊天应用部署与定制指南
  • 大模型训练优化框架Socratic-Zero解析与应用
  • GPTs提示词设计指南:从原理到实践,打造专属AI助手
  • 1688运营培训/1688运营培训,16年老店铺月询盘暴涨171%
  • 基于LoRA的对话模型微调实战:从开源模型到专属AI助手
  • 熵减开发悖论突破方案:软件测试的破局之道
  • 长沙理工大学考研辅导班机构推荐:排行榜单与哪家好评测 - michalwang
  • 2026 热门网页游戏推荐,耐玩不氪金的网页游戏大盘点
  • AI赋能:让快马平台生成能理解内容与风格的智能Pinterest下载器
  • 用STC15单片机+DS1302做个简易电子钟?附完整工程代码和数码管显示避坑指南
  • 深度拆解Scrapy Selector:XPath实战手册,从入门到高吞吐量抓取架构
  • Kubernetes Operator开发脚手架:从CRD定义到生产就绪的完整实践
  • 抛丸区高大空间供暖选垂直送风型适配吗?