ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

随机森林鸢尾花分类实战:从代码拆解到可复用模板

随机森林鸢尾花分类实战:从代码拆解到可复用模板 简介这份资源面向机器学习初学者与需要快速上手随机森林的开发者围绕经典的花卉分类任务提供一份可直接运行的Python实现。压缩包内共1个文件为单个py脚本整体约1KB轻量易读适合作为课堂演示或自学练手素材。脚本以鸢尾花数据集为典型场景完整串联数据读取、特征与目标变量划分、训练集与测试集切分、随机森林分类器构建、超参数设置以及准确率、精确率、召回率、F1分数与混淆矩阵等评估环节并涉及特征重要性分析与新样本预测思路帮助读者理解Bootstrap抽样与多决策树集成降低过拟合的机制。目前已有297人学习下载可作为入门集成学习、完成课程作业或搭建分类基线模型的参考代码。1. 花分类随机森林源代码拆包hua.zip 里到底有什么鸢尾花分类几乎是每个搞机器学习的人绕不开的第一个完整案例但真正把「数据读入 → 训练 → 评估 → 预测新样本」串成一条可运行流水线的代码包并不多。hua.zip 就是这样一个东西里面一个 hua.py用随机森林做花的四特征三分类从加载数据到输出预测结果全流程走通。它解决的不是「随机森林是什么」这种概念问题而是「给我一份能跑、能改、能套到自己数据上的最小可用代码」。适合刚学完 sklearn 基础 API、想找一个完整案例练手的人也适合需要快速搭一个分类基线、再往上加特征工程的老手。代码不长但麻雀虽小该有的环节一个不少。2. 随机森林做花分类为什么选它、怎么搭环境2.1 为什么花分类适合用随机森林入门鸢尾花数据集只有 150 条样本、4 个特征、3 个类别数据干净得不像真实项目。但正是这种干净让它成为验证算法行为的理想试验台。随机森林在这个数据集上的表现通常能到 95% 以上的准确率而且不需要太多调参就能跑出像样的结果。选随机森林而不是单棵决策树核心理由是方差控制。单棵决策树对训练数据的微小变化非常敏感——你换一个随机种子树的结构可能完全不同预测结果也跟着抖。随机森林通过 Bootstrap 抽样构建多棵树每棵树只看部分样本和部分特征最后投票决定分类结果。这种「集体决策」机制把单棵树的方差摊薄了泛化能力明显更稳。另一个实际好处是特征重要性。训练完之后可以直接拿到每个特征对分类的贡献度对于鸢尾花这种只有四个特征的数据集来说能直观看到花瓣长度和花瓣宽度是不是真的比萼片特征更重要。这对理解数据和向别人解释模型都有用。还有一点容易被忽略随机森林对特征缩放不敏感。不需要做标准化或归一化原始特征直接扔进去就能跑。对于刚入门的人来说少一步预处理就少一个出错的地方。2.2 环境准备与依赖安装hua.py 依赖的库都是 Python 机器学习生态里最标准的几个不需要额外配置什么冷门依赖。我一般会先建一个干净的虚拟环境避免和系统里已有的包版本打架。# 创建虚拟环境Python 3.8 均可 python -m venv hua_env # 激活环境 # Windows: hua_env\Scripts\activate # macOS / Linux: source hua_env/bin/activate # 安装核心依赖 pip install numpy pandas scikit-learn这三个包的分工很明确numpy 负责底层数组运算pandas 负责数据加载和表格操作scikit-learn 提供 RandomForestClassifier 以及数据集加载、训练测试划分、评估指标等全套工具。版本方面没有特别苛刻的要求scikit-learn 0.24 以上都行但建议用较新的版本因为旧版本在某些参数默认值上有差异。提示如果你用的是 Anaconda上述三个库通常已经预装可以直接跳过安装步骤但仍建议确认 scikit-learn 版本不低于 0.24。装完之后可以跑一行验证import sklearn print(sklearn.__version__)能正常输出版本号就说明环境没问题。接下来就可以直接运行 hua.py 了。2.3 hua.py 的代码结构与执行流程拿到 hua.py 之后我习惯先通读一遍再运行搞清楚它的执行链路。这个脚本的结构很清晰基本按机器学习的标准流程走加载数据 → 划分训练测试集 → 构建随机森林 → 训练 → 评估 → 预测新样本。核心代码大致是这样的import numpy as np import pandas as pd from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score, classification_report, confusion_matrix # 加载鸢尾花数据集 iris load_iris() X iris.data # 特征矩阵shape (150, 4) y iris.target # 标签向量shape (150,) # 划分训练集和测试集测试集占 30% X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) # 构建随机森林分类器 rf RandomForestClassifier( n_estimators100, # 树的数量 max_depthNone, # 树的最大深度None 表示不限制 min_samples_split2, # 内部节点再划分所需最小样本数 min_samples_leaf1, # 叶节点最少样本数 random_state42 # 随机种子保证结果可复现 ) # 训练模型 rf.fit(X_train, y_train) # 在测试集上预测 y_pred rf.predict(X_test) # 评估 print(准确率:, accuracy_score(y_test, y_pred)) print(\n分类报告:) print(classification_report(y_test, y_pred, target_namesiris.target_names)) print(\n混淆矩阵:) print(confusion_matrix(y_test, y_pred))这段代码里几个关键点值得展开说。stratifyy保证了训练集和测试集中三个类别的比例一致避免某个类别在测试集里一条都没有。random_state42固定了随机种子让每次运行的结果完全一样方便调试和对比。n_estimators100是默认值对于这个规模的数据集来说够用了再往上加收益很小。2.4 关键参数怎么调n_estimators、max_depth 与特征重要性随机森林的参数不少但真正影响大的就那么几个。我按实际调参的经验排个优先级。n_estimators树的数量这是最直观的参数。树越多模型越稳定但计算开销也线性增长。对于鸢尾花这种小数据集50 到 200 之间差别不大100 是个合理的默认值。如果你换成几千条样本的数据集可能需要 200 到 500 棵树才能看到稳定收益。判断方法很简单画一条 n_estimators 对准确率的曲线看什么时候趋于平缓。max_depth最大深度控制每棵树能长多深。不限制深度的话每棵树会一直分裂到叶节点纯净为止训练集准确率能到 100%但测试集可能反而下降。对于鸢尾花数据因为本身特征区分度好不限制深度也不会过拟合得太厉害。但如果你换成噪声更大的数据建议从 5 到 15 之间试起。min_samples_split 和 min_samples_leaf这两个是防止过拟合的细粒度控制。min_samples_split 默认 2意味着只要节点里有 2 个以上样本就继续分裂。调大这个值可以抑制树长得太细。min_samples_leaf 控制叶节点的最小样本数调大它能让每个叶子覆盖更多样本减少对噪声的拟合。max_features每次分裂考虑的特征数这个参数在 sklearn 里默认是sqrt即每次分裂只看总特征数的平方根个特征。对于 4 个特征的鸢尾花数据每次只看 2 个特征。这是随机森林「随机」的核心来源之一一般不需要改。训练完之后用一行代码就能看特征重要性# 查看特征重要性 importances rf.feature_importances_ for name, imp in zip(iris.feature_names, importances): print(f{name}: {imp:.4f})在鸢尾花数据集上通常花瓣长度和花瓣宽度的权重加起来会超过 0.8萼片宽度的贡献最小。这个结果和领域知识一致——花瓣的尺寸确实更能区分不同品种。3. 从训练到预测完整流程的复现与验证3.1 数据加载与训练测试划分的细节load_iris()返回的是一个 Bunch 对象包含 data、target、feature_names、target_names 等字段。data 是 150×4 的 numpy 数组target 是 0/1/2 的整数标签分别对应 setosa、versicolor、virginica 三个品种。train_test_split的test_size0.3意味着 150 条数据里 105 条用于训练、45 条用于测试。这个比例在样本量小的时候比较合适如果数据集有上万条测试集占比可以降到 0.1 到 0.2。stratifyy这个参数容易被忽略但在类别不均衡的数据上非常关键。鸢尾花三个类别各 50 条本身是均衡的加不加 stratify 差别不大。但养成习惯是好事——换成不均衡数据时不加 stratify 可能导致某个类别在测试集里只有一两条评估结果完全不可信。3.2 模型训练与评估指标解读训练就是一行rf.fit(X_train, y_train)没什么好说的。重点是评估环节怎么看结果。accuracy_score给出的是整体准确率在类别均衡的数据上够用。但光看准确率不够还要看classification_report里的 precision、recall 和 f1-score。precision 回答的是「预测为某个品种的样本里有多少真的是这个品种」recall 回答的是「某个品种的样本里有多少被正确找出来了」。f1-score 是两者的调和平均。在鸢尾花数据上setosa 通常能被完美分类precision 和 recall 都是 1.0因为它在特征空间里和另外两个品种离得很远。versicolor 和 virginica 之间有一些重叠区域偶尔会互相误判precision 和 recall 可能在 0.9 到 1.0 之间浮动。混淆矩阵更直观from sklearn.metrics import ConfusionMatrixDisplay import matplotlib.pyplot as plt ConfusionMatrixDisplay.from_estimator(rf, X_test, y_test, display_labelsiris.target_names) plt.show()对角线上的数字是正确分类的数量非对角线是误判。如果 versicolor 和 virginica 之间有误判你会看到这两个类别对应的格子有非零值。3.3 用新样本做预测输入一条花的数据看结果训练好的模型最终要能对新数据做预测。hua.py 里通常会有类似这样的代码# 模拟一条新的花数据 # 格式[萼片长度, 萼片宽度, 花瓣长度, 花瓣宽度] new_sample np.array([[5.1, 3.5, 1.4, 0.2]]) # 预测类别 prediction rf.predict(new_sample) predicted_name iris.target_names[prediction[0]] print(f预测品种: {predicted_name}) # 查看各类别概率 probabilities rf.predict_proba(new_sample) for name, prob in zip(iris.target_names, probabilities[0]): print(f{name}: {prob:.4f})predict返回的是类别标签predict_proba返回的是属于每个类别的概率。概率信息在实际场景里很有用——如果三个类别的概率都在 0.3 到 0.4 之间说明模型对这条样本不太确定可能需要人工复核。输入新样本时要注意特征顺序必须和训练时一致。鸢尾花数据集的顺序是萼片长度、萼片宽度、花瓣长度、花瓣宽度如果你搞反了预测结果会完全错误。这是实际部署时最常见的翻车点之一。3.4 交叉验证比单次划分更可靠的性能估计单次 train_test_split 的结果有一定随机性——换一个 random_state准确率可能差几个百分点。要更可靠地估计模型性能交叉验证是标准做法from sklearn.model_selection import cross_val_score # 5 折交叉验证 scores cross_val_score(rf, X, y, cv5, scoringaccuracy) print(f各折准确率: {scores}) print(f平均准确率: {scores.mean():.4f} (/- {scores.std():.4f}))5 折交叉验证把数据分成 5 份每次用 4 份训练、1 份验证轮流进行 5 次。最终得到 5 个准确率取平均作为性能估计标准差反映稳定性。在鸢尾花数据上通常能看到平均准确率在 0.95 左右标准差在 0.03 以内。交叉验证的代价是计算量翻了几倍但对于这个规模的数据集来说完全可以接受。如果数据量很大可以用cv3减少折数或者用StratifiedKFold手动控制。4. 避坑与排查花分类随机森林代码的五个常见问题4.1 准确率异常低或为 0现象运行代码后准确率只有 0.3 左右甚至接近 0。原因最常见的是特征和标签搞反了把X和y传反了位置。另一种可能是数据加载时用了错误的列比如把标签列也当成了特征。解决检查rf.fit(X_train, y_train)的参数顺序确认 X 是二维特征矩阵、y 是一维标签向量。打印X.shape和y.shape确认维度正确——X 应该是(n_samples, n_features)y 应该是(n_samples,)。4.2 每次运行结果都不一样现象同样的代码每次运行输出的准确率和混淆矩阵都不同。原因RandomForestClassifier的random_state参数没有设置或者train_test_split的random_state没有设置。随机森林本身包含随机抽样过程不固定种子的话每次结果都会变。解决在train_test_split和RandomForestClassifier中都加上random_state42或其他固定整数。这样每次运行的数据划分和树构建过程完全一致结果可复现。4.3 测试集准确率远高于交叉验证结果现象单次 train_test_split 的准确率是 1.0但交叉验证平均只有 0.95。原因单次划分的测试集可能恰好比较简单或者测试集里某个类别的样本特别容易被区分。这不是代码错误而是单次评估的随机性导致的。解决以交叉验证的结果为准。如果两者差距很大说明单次划分的测试集不具有代表性。可以多换几个 random_state 跑几次观察准确率的波动范围。4.4 新样本预测报错维度不匹配现象用rf.predict(new_sample)时报错提示特征数不匹配。原因新样本的维度不对。训练时用了 4 个特征预测时如果只传了 3 个值或者传成了(4,)的一维数组而不是(1, 4)的二维数组都会报错。解决确保新样本是二维数组shape 为(1, n_features)。用np.array([[5.1, 3.5, 1.4, 0.2]])而不是np.array([5.1, 3.5, 1.4, 0.2])。多一个方括号的区别但结果完全不同。4.5 特征重要性全为 0 或分布异常现象打印feature_importances_发现所有特征的重要性都是 0或者某个特征的重要性是 1.0 其他全是 0。原因如果所有树都只用了同一个特征做分裂说明其他特征对分类没有贡献。这在鸢尾花数据上不太可能出现但如果换成噪声数据或者特征之间有完全共线性就可能发生。另一种可能是模型根本没训练成功fit没有正确执行。解决先确认rf.fit()没有报错然后检查数据本身是否有问题。如果确实存在无用特征考虑做特征选择。在鸢尾花数据上正常情况应该是花瓣长度和花瓣宽度的重要性明显高于萼片特征但不会出现某个特征独占 1.0 的情况。5. 进阶技巧把 hua.py 改造成可复用的分类模板5.1 封装成函数从脚本到可调用模块hua.py 作为脚本直接运行没问题但如果你想把它用到自己的数据上每次改代码很麻烦。我一般会把它封装成几个函数输入特征矩阵和标签向量就能跑def train_rf_classifier(X, y, n_estimators100, test_size0.3, random_state42): 训练随机森林分类器并返回模型和评估结果 X_train, X_test, y_train, y_test train_test_split( X, y, test_sizetest_size, random_staterandom_state, stratifyy ) rf RandomForestClassifier( n_estimatorsn_estimators, random_staterandom_state, n_jobs-1 # 并行训练利用所有 CPU 核心 ) rf.fit(X_train, y_train) y_pred rf.predict(X_test) acc accuracy_score(y_test, y_pred) report classification_report(y_test, y_pred) return rf, acc, report这样封装之后换数据集只需要改传入的 X 和 y不用动训练逻辑。n_jobs-1让训练过程并行化在大数据集上能明显缩短时间。5.2 用 GridSearchCV 自动调参手动调 n_estimators 和 max_depth 效率低用 GridSearchCV 可以自动搜索最优参数组合from sklearn.model_selection import GridSearchCV param_grid { n_estimators: [50, 100, 200], max_depth: [None, 5, 10, 15], min_samples_split: [2, 5, 10] } grid_search GridSearchCV( RandomForestClassifier(random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1 ) grid_search.fit(X_train, y_train) print(最优参数:, grid_search.best_params_) print(最优交叉验证准确率:, grid_search.best_score_)这个网格有 3×4×336 种组合每种跑 5 折交叉验证总共 180 次训练。在鸢尾花数据上几秒钟就能跑完。换成大数据集时要注意计算开销可以先用较粗的网格缩小范围再在最优区域附近细化。5.3 模型持久化训练一次到处使用每次用的时候重新训练不现实尤其是数据量大或者参数复杂的时候。用 joblib 把训练好的模型存到磁盘import joblib # 保存模型 joblib.dump(rf, rf_iris_model.pkl) # 加载模型 loaded_rf joblib.load(rf_iris_model.pkl) # 直接用加载的模型预测 new_pred loaded_rf.predict(np.array([[6.3, 2.9, 5.6, 1.8]])) print(预测结果:, iris.target_names[new_pred[0]])存下来的 pkl 文件包含了模型的所有参数和树结构加载后可以直接预测不需要重新训练。注意 sklearn 版本要一致用不同版本训练和加载可能会报兼容性错误。5.4 从鸢尾花到自定义数据替换数据集时要注意什么把 hua.py 套到自己的数据上核心改动就两处把load_iris()换成你自己的数据加载逻辑把特征名和类别名换成你自己的。但有几个坑要提前知道。第一确保特征都是数值型。如果有类别型特征需要先做编码LabelEncoder 或 OneHotEncoder随机森林不能直接处理字符串特征。第二检查缺失值。sklearn 的随机森林不接受 NaN需要提前用 SimpleImputer 填充或者删掉含缺失值的行。第三类别标签需要是整数。如果是字符串标签用 LabelEncoder 转成 0、1、2 这样的整数。第四如果类别严重不均衡设置class_weightbalanced让模型自动调整权重避免模型偏向多数类。我自己的习惯是每次换数据集先跑一遍df.info()和df.describe()确认数据类型、缺失值情况和数值分布然后再往模型里送。这个步骤花不了两分钟但能省掉后面大量的排查时间。从那以后我每次拿到新数据都强制走一遍这个检查流程希望帮到你。本文还有配套的精品资源点击获取
返回列表