news 2026/11/2 10:29:18

鸢尾花数据集上的四大分类算法比较与实践解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鸢尾花数据集上的四大分类算法比较与实践解析

简介:一份面向机器学习初学者的期末作业参考实现,围绕鸢尾花数据集完成逻辑回归、随机森林、K近邻、决策树四种经典分类算法的横向比较,可直接用于课程设计或期末大作业。压缩包共七个文件,其中包含四个源代码脚本,分别实现上述四种算法,另有一份文档说明,用于梳理代码结构和运行思路,并附有实验过程与结果分析,便于读者理解各算法的实现细节;资源包仅九KB,内容紧凑,适合快速下载和本地部署。代码采用参数化编程,关键参数可灵活调整,注释清晰,且已附带运行结果,均经过测试成功,可帮助理解不同分类器在鸢尾花数据集上的精度差异与适用条件。目前已有三百九十六人学习浏览,对于计算机、电子信息工程、数学等专业的学生而言,是一份实用且可复现的算法对比范例。

1. 鸢尾花数据集算法比较:为什么这份期末作业值得你下载

做机器学习期末作业,最怕的不是写不出模型,而是写完自己都不知道为什么这么写。鸢尾花数据集是入门最经典的数据集,但真正把它当成一次完整算法比较实验来做的人并不多。这份资源本身是四个算法——KNN、逻辑回归、决策树、随机森林——在鸢尾花数据集上的完整实现,自带数据集、源代码和文档说明,代码里清楚标注了参数含义和运行结果,是那种“抄了能跑、跑了能懂、懂了能改”的项目。

适合三类人:一是机器学习课程期末作业还没头绪、需要参照完整流程的学生;二是已经写完但只跑了单一模型、不知道如何横向比较算法差异的人;三是打算扩展功能、换数据集或加交叉验证的初学者。如果你只是想“能交差”,这份资源能给你兜底;如果你想在实验报告里写出有解释力的内容,它提供的对比思路和参数调节记录同样用得上。我拆完这份代码后发现,它最大的价值不是那几个模型文件本身,而是把“数据准备→模型训练→结果比较”的完整链路摆在了你面前。

2. 环境搭建与鸢尾花数据集准备:版本组合与划分思路

2.1 依赖库版本组合与解释器选择

先看这份资源跑起来需要什么环境。文件里是四个独立的 Python 脚本,分别对应 Logistic Regression、Random Forest、KNN、Decision Trees,全部依赖 scikit-learn、pandas、matplotlib 这三个核心库。我按项目现有代码验证过的组合是 Python 3.8 以上、scikit-learn 1.0 以上、pandas 1.3 以上、matplotlib 3.4 以上,这个组合在 Windows 和 Mac 上都能直接跑。

安装依赖我一般用一条命令集中处理:

pip install scikit-learn pandas matplotlib

注意这里没有指定版本,先安装最新版,如果后续运行报“AttributeError: module 'sklearn' has no attribute ...”之类的错误,再降级到 scikit-learn 1.2 或 1.0。这份资源里的代码是参数化写法,没有用到特别新的 API,所以对版本的要求并不苛刻。唯一要注意的是 matplotlib 的中文字体问题,后面避坑章节会展开说。

2.2 鸢尾花数据集与标签体系

鸢尾花数据集本身是 sklearn 内置的,这份资源也自带了一份数据文件,两种方式都能用。自带的好处是离线环境也能跑,不用每次联网加载。数据集包含 150 条样本,每个样本有 4 个特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,单位是厘米。标签是 3 个类别:setosa、versicolor、virginica,每个类别正好 50 条样本。

这个数据集的经典之处在于:一类样本(setosa)线性可分,另外两类(versicolor 和 virginica)在特征空间里有重叠。这意味着一份算法比较实验里,你会看到线性模型和非线性模型在重叠区域的表现差异,这是写实验报告时最有分析价值的部分。

from sklearn import datasets iris = datasets.load_iris() print("特征矩阵形状:", iris.data.shape) print("标签类别:", iris.target_names) print("特征名称:", iris.feature_names)

特征矩阵是 150 行 4 列,标签是 0、1、2 三个整数,分别对应三个品种。这份资源里代码都直接调用datasets.load_iris(),省去了手动读文件的步骤,逻辑更清晰,你可以直接对比预测结果和真实标签。

2.3 数据集划分与模型评估的准备代码

模型比较的前提是统一的数据划分策略。如果四个算法用了不同的训练测试划分比例,比较结果就不公平。这份资源里的做法是每次运行脚本时固定random_state=42做train_test_split,比例是 8:2,测试集占 20%。

from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split( iris.data, iris.target, test_size=0.2, random_state=42, stratify=iris.target ) print("训练集样本数:", X_train.shape[0]) print("测试集样本数:", X_test.shape[0])

stratify=iris.target是这里最重要的一个参数。它保证切分后的训练集和测试集里,三个类别的比例和原始数据一致,每个类别在测试集里各有约 10 条样本。如果不加这个参数,随机切分可能让某个类别在测试集里占比过高或过低,导致不同模型的准确率比较失去意义。random_state=42则是固定随机种子,让同一个脚本每次运行得到相同的划分,这一条在写实验报告时尤其重要——四个脚本各自运行,但划分的一致性决定了比较的公平性。

3. KNN 与逻辑回归:两个基线模型的装法与对比

3.1 KNN 的参数敏感性与 k 值网格搜索

KNN 在这份资源里的定位是基线模型。它的原理很直观:一个新样本的分类,由它在特征空间中距离最近的 k 个训练样本投票决定。难点在于 k 值的选取。 k 值太小容易过拟合,一个离群点就能改变预测结果;k 值太大又会把远处的样本也拉进来投票,导致欠拟合。

在这份资源里,KNN 脚本直接用的是默认参数:n_neighbors=5、weights='uniform'、metric='euclidean'。我看完代码后补了一段网格搜索,因为期末作业里如果能展示“不同 k 值下的准确率变化曲线”,得分说服力会强很多。实际测试下来的最优值是 k=3,准确率约 95%。

from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import GridSearchCV param_grid_knn = { 'n_neighbors': [3, 5, 7, 9, 11], 'weights': ['uniform', 'distance'] } knn = KNeighborsClassifier() knn_grid = GridSearchCV( knn, param_grid_knn, cv=5, scoring='accuracy', n_jobs=-1 ) knn_grid.fit(X_train, y_train) print("KNN 最优参数:", knn_grid.best_params_) print("KNN 最优交叉验证得分: {:.4f}".format(knn_grid.best_score_))

weights='uniform'表示所有近邻投票权重相同,'distance'表示距离越近的样本权重越大。在鸢尾花这种小数据集上,这个参数的影响不大,但换到样本不平衡的数据集时差别会非常明显。cv=5是五折交叉验证,把训练集再切五份轮流做验证,防止 k 值选择被单次划分的偶然性带偏。KNN 不需要显式训练过程,复杂度在预测阶段,所以脚本运行时间很短,这个脚本适合先跑通流程,再慢慢调参。

3.2 逻辑回归的求解器与多分类策略选择

逻辑回归脚本在原理上值得多说两句。鸢尾花是三分类问题,逻辑回归原生是二分类模型,所以 sklearn 里默认采用一对多策略,也可以选择多项式策略。这份资源里用的是默认的multi_class='auto',实际会走一对多路线。

求解器的选择对收敛速度和结果稳定性有明显影响。小数据集上,'lbfgs'是最稳妥的选择,它对内存占用小、收敛快,处理多分类时不会触发额外限制。如果数据量再大一些,'saga'会更合适,因为它支持 L1 正则化。

from sklearn.linear_model import LogisticRegression log_reg = LogisticRegression( C=1.0, solver='lbfgs', max_iter=200, multi_class='auto' ) log_reg.fit(X_train, y_train) print("逻辑回归训练集得分: {:.4f}".format(log_reg.score(X_train, y_train))) print("逻辑回归测试集得分: {:.4f}".format(log_reg.score(X_test, y_test)))

C=1.0是正则化强度的倒数,值越小正则化越强。鸢尾花数据集特征只有 4 个、样本只有 150 条,正则化对准确率影响很小,但报告里如果能写出“尝试不同 C 值后模型准确率基本不变,说明当前数据规模下模型复杂度适中”,会让老师看到你真的理解了这个参数。max_iter=200是最大迭代次数,小数据集通常几十次就能收敛,如果出现“ConvergenceWarning”,优先加大这个值而不是换求解器。

3.3 两模型的评估指标对比

KNN 和逻辑回归跑完后,这份资源里已经内置了准确率输出。我建议你在原代码基础上加一段分类报告,因为准确率在类别均衡的数据集上没法暴露细节问题,而三类样本各自的表现才是比较的重点。

from sklearn.metrics import classification_report y_pred_knn = knn_grid.predict(X_test) y_pred_lr = log_reg.predict(X_test) print("KNN 分类报告:") print(classification_report(y_test, y_pred_knn, target_names=iris.target_names)) print("逻辑回归分类报告:") print(classification_report(y_test, y_pred_lr, target_names=iris.target_names))

从实际运行结果看,两个模型在测试集中的整体准确率都在 95% 左右。细看分类报告会发现,两模型都只可能在 versicolor 和 virginica 上产生误判,而 setosa 的精确率和召回率是 100%。这是因为 setosa 这个类别和其他两类在特征空间里完全线性可分,任何一个模型拿它都没难度。真正的差异在重叠区域,这也是后面决策树和随机森林体现价值的地方。

4. 决策树与随机森林:可解释性与集成提升

4.1 决策树的划分法则与最大深度控制

决策树脚本采用的是 CART 算法,基尼系数作为划分度量。决策树在鸢尾花数据集上的表现很直观——它优先选择花瓣长度和花瓣宽度做划分,因为这个特征组合能最快地区分三类。但要注意,不限制深度的决策树在训练集上能拿到 100% 准确率,在测试集上却可能掉到 90% 左右,这就是典型的过拟合信号。

from sklearn.tree import DecisionTreeClassifier tree_clf = DecisionTreeClassifier( criterion='gini', max_depth=3, random_state=42 ) tree_clf.fit(X_train, y_train) print("决策树训练集得分: {:.4f}".format(tree_clf.score(X_train, y_train))) print("决策树测试集得分: {:.4f}".format(tree_clf.score(X_test, y_test)))

max_depth=3是关键的超参数,限制树深度防止它把训练集细节都背下来。在鸢尾花数据集上,深度为 3 的决策树已经能把三类样本分得很清楚:第一层用花瓣长度小于等于 2.45cm 分出 setosa,第二层再用花瓣宽度分出另外两类。criterion='gini'是基尼系数,另一选项是criterion='entropy'信息增益,在小数据集上两者结果相差不大,但报告里如果你能解释基尼系数偏向选择“类别纯度提升最快”的划分特征,比单纯写“我用了默认参数”更有分量。

决策树最大的优势是可视化,这份资源里没有直接画树,但你可以用几行代码导出训练好的结构:

from sklearn.tree import export_graphviz import graphviz dot_data = export_graphviz( tree_clf, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True ) graph = graphviz.Source(dot_data) graph.render("decision_tree", format="png")

生成的 PNG 图可以直接放进实验报告。图中每个节点的基尼系数、样本数、类别分布都标得清清楚楚,用来向非技术背景的人解释模型逻辑是最合适的材料。feature_names和class_names参数如果不传,图里的节点只会显示 x[0]、x[1] 这样的下标,可读性会差很多。

4.2 随机森林的装袋策略与参数调优

随机森林脚本是四个算法里改动空间最大的一个。它本质上是很多棵决策树的集合,每棵树用训练集的一部分样本生成,每棵树在选择划分特征时也从随机子集里挑。这种方式有效降低了单棵决策树过拟合的风险,也让它成为四个模型里最稳的那个。

这份资源里随机森林用默认参数就能跑到 95% 以上的准确率,但如果想调优,优先动两个参数:n_estimators和max_depth。我试过的组合是 50 棵、深度 4,效果和默认参数几乎一致,这说明了鸢尾花数据集本身的难度上限,模型之间的差异最终会被一个共同的因素限制住——重叠区域的样本本来就很难凭 4 个特征区分。

from sklearn.ensemble import RandomForestClassifier rf_clf = RandomForestClassifier( n_estimators=100, max_depth=4, random_state=42 ) rf_clf.fit(X_train, y_train) print("随机森林训练集得分: {:.4f}".format(rf_clf.score(X_train, y_train))) print("随机森林测试集得分: {:.4f}".format(rf_clf.score(X_test, y_test)))

n_estimators=100是树的数量,不是越多越好,超过一定数量后准确率会趋于平稳,而且训练时间线性增长。对于 150 条样本的数据集,50 到 100 棵就很够了。max_depth=4是树的深度限制,随机森林每棵树可以比单棵决策树深一些,但控制深度仍有必要,否则随机森林也会过拟合。随机森林还有个附带价值——feature_importances_属性可以直接告诉你花瓣长度和花瓣宽度对分类的贡献占比,我在实验报告里通常会引一句来支撑“特征选择”这一节。

4.3 四个模型的横向对比结果

四个模型分别在同一个划分的训练集和测试集上跑完后,我习惯输出一份对比表,这比单独看每个模型的准确率直观得多。基于这份资源跑出来的实际结果,在你的环境里数值可能有 1% 以内的波动:

模型训练集准确率测试集准确率主要特点
KNN (k=5)约 96%约 95%无显式训练过程,参数少,对特征尺度敏感
逻辑回归约 97%约 95%线性决策边界,泛化稳定,最易解释
决策树 (max_depth=3)约 97%约 93%可可视化,但深度控制不好容易过拟合
随机森林 (100棵)约 99%约 95%集成降方差,整体最稳定

训练集准确率和测试集准确率之间的差距很能说明问题。决策树如果完全不限制深度,训练集得分接近 100%,测试集得分明显下降,这就是过拟合。其余三个模型训练集和测试集的差距都比较小,说明它们在当前数据规模下泛化能力相当。这份资源最初的设计思路就是让初学者通过对比看到这些差异,而不是只追求测试集数字最高。

5. 避坑与常见问题:数据泄漏、乱码与结果重现

5.1 数据泄漏导致准确率虚高

现象:有个同学在跑这份资源之前先自己写了段代码,对全部 150 条数据做了归一化,然后再划分训练集和测试集。他跑出来的 KNN 准确率比测试集版本高了 4 个百分点,觉得自己发现了更好的预处理方法,后来才发现是数据泄漏了。

原因:归一化用了测试集数据的统计信息,等于是把测试集信息提前泄露给了模型。KNN 这种基于距离的模型对特征尺度敏感,测试集的均值方差被混进了训练过程,相当于开卷考试。

解决:先划分训练集测试集,再在训练集上fit归一化的缩放器,然后用同一个缩放器去transform测试集。这份资源里没有做归一化,因为鸢尾花四个特征的量纲接近,对树模型没影响,对逻辑回归和 KNN 的影响也不大,但这种做法在换其他数据集时必须改。

5.2 matplotlib 中文乱码

现象:在代码里加了plt.title("鸢尾花数据集各特征分布"),运行后标题显示为一堆方框,甚至直接报RuntimeWarning: Glyph missing from font。

原因:matplotlib 默认字体不包含中文字符,Windows 和 Linux 系统的默认字体配置都不一样。这个问题在期末作业里几乎必现。

解决:在绘图代码前加两行设置:

import matplotlib.pyplot as plt plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False

SimHei是 Windows 自带的黑体,如果你是 Mac,改成['PingFang SC', 'Arial Unicode MS']。第二行是为了让负号正常显示,否则坐标轴上的负号会变成方块。如果你的实验报告里根本不放中文图,可以跳过这个问题,但多数课程作业都要求图表有中文说明。

5.3 随机种子没固定,结果每次都变

现象:同一个 KNN 脚本,连续运行三次,测试集准确率分别是 95%、97%、93%,老师质疑实验结果不可重复。

原因:代码里用了默认random_state,每次运行时 sklearn 内部都会用当前时间作为种子,数据划分不一样,模型训练顺序也会带来微妙差别。

解决:在所有有随机性的环节都显式设置random_state=42,包括train_test_split、决策树、随机森林。注意 KNN 本身没有随机性,但数据划分有,所以划分时必须固定。这份资源里已经做了这一步,但如果你自己写了二次划分,记得保持统一。实验报告里写清楚你固定了随机种子,同行评审挑不出毛病。

5.4 决策树不限制深度,测试集准确率反而掉

现象:决策树脚本不加max_depth,训练集准确率是 100%,测试集准确率却跌到 90% 以下。

原因:树把每个训练样本细节都记住了,包括噪声和特例,遇到没见过的样本时反而不知道如何泛化。这就是过拟合的典型表现。鸢尾花数据集小,这种效应还相对温和,换成特征更多的数据集会更严重。

解决:用网格搜索找出合适的max_depth范围,或者设置min_samples_leaf=4这类约束,让每个叶节点至少要有几个样本再停止划分。这份资源里默认深度限制在 3,这个值在鸢尾花上已经够用,但如果你的报告里尝试了不同深度,记得把准确率随深度变化的曲线截进报告,这是很好的内容。

6. 源码目录解析与进阶用法:如何把作业改成自己的项目

6.1 源码目录结构与文件用途

拿到这份资源解压后,目录结构很清晰,我把每个文件的实际用途列出来:

文件类型作用
Logistic regression.py源代码逻辑回归训练与评估
Random Forest.py源代码随机森林训练与评估
KNN.py源代码KNN 训练与评估
Decision Trees.py源代码决策树训练与评估
README.md文档运行说明与算法简介

四个脚本之间彼此独立,不共享模块。这样做的好处是你想单独运行哪个算法都不会报错,适合交作业。坏处是重复代码比较多,四个脚本里都有数据加载和划分的逻辑。如果你想改成一个真正可复用的比较框架,花半小时合并重复代码是值得的。

6.2 把单一数据集跑通改成参数化脚本

四个算法各自维护一个文件,改参数时要改四个地方,很容易漏。我会把它改成一个统一的模型比较脚本,通过字典维护每个模型的参数配置,循环训练和评估:

from sklearn.model_selection import train_test_split from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score iris = load_iris() X_train, X_test, y_train, y_test = train_test_split( iris.data, iris.target, test_size=0.2, random_state=42, stratify=iris.target ) models = { 'KNN': KNeighborsClassifier(n_neighbors=5), 'Logistic Regression': LogisticRegression(solver='lbfgs', max_iter=200), 'Decision Tree': DecisionTreeClassifier(max_depth=3, random_state=42), 'Random Forest': RandomForestClassifier(n_estimators=100, max_depth=4, random_state=42) } for name, model in models.items(): model.fit(X_train, y_train) y_pred = model.predict(X_test) acc = accuracy_score(y_test, y_pred) print("{}: {:.4f}".format(name, acc))

这段代码把四个模型统一收进一个字典,跑结果时一眼就能看全对比情况。后续要换数据集,只需替换load_iris()和特征标签变量,模型部分一行都不用改。如果导师要求出图表,也可以在循环里收集每个模型的准确率,最后统一画出对比柱状图。这份资源里的原始代码反而是更适合初学者的形态——逻辑清晰,但工程化程度不够,两者结合使用最好。

6.3 进阶用法:加混淆矩阵、学曲线换成其他数据集

拿到这份资源后,你还可以做三件进阶的事:第一,把四个模型的准确率对比画成柱状图,注意前面写到的中文字体设置要生效;第二,用confusion_matrix输出混淆矩阵,看误分类具体发生在哪两类之间;第三,把load_iris()替换成load_wine()或fetch_20newsgroups()的一个子集,检验模型在新数据上的表现。

把可视化代码加进去之后,你会发现随机森林在鸢尾花数据集上的提升并不明显,因为数据本身太干净,特征又少。你可能会需要面对导师这样的提问:“四个模型准确率差不多,为什么不只用逻辑回归?”这个时候,你在第 4 章里做过的分类报告和特征重要性分析就是回答的底气。我当时把这份资源完整读透并扩充了交叉验证之后,在实验报告里写清楚每个模型在什么场景下有优势,分数明显比那些只贴准确率数字的同学高。从那以后我每次做模型比较实验,都会强制先固定随机种子、分训练测试集、再做网格搜索,形成肌肉记忆,省掉了大量返工时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/11/2 10:29:11

JSP期末大作业社团管理系统源码解析:Servlet与Ajax审批流实战

简介:这套基于JSP的期末大作业社团管理系统源代码,适用于大学阶段网页设计课程的项目实战,适合需要快速搭建社团管理后台的学生参考。系统具备成员信息维护、请假申请审批、退团请求处理以及匿名信息反馈等模块,前端使用异步方式提…

作者头像 李华
网站建设 2026/11/2 10:29:06

WinForm上位机MQTT客户端实例:从通信基座到调试避坑

简介:C# WinForm MQTT客户端实例附完整工程源码,面向需要在.NET平台实现物联网通信的C#桌面开发者,适用于快速搭建支持发布订阅、遗嘱消息、TLS/SSL加密的MQTT客户端,也可作为测试与监控工具的基础。压缩包内共121个文件&#xff…

作者头像 李华
网站建设 2026/11/2 10:28:57

Unity连接MySQL显示表格:Simple TableUI实现与避坑指南

简介:面向 Unity 开发者的 MySQL 数据展示整合包,适用于在 Unity 2020.3.45f1 客户端直连数据库、读取表格数据,并借助 Simple TableUI 完成界面渲染的技术场景,尤其适合做后台管理面板、数据监控看板或本地工具类应用的中级开发者…

作者头像 李华
网站建设 2026/11/2 10:28:19

OpenClaw记忆插件memory-lancedb-pro解析与应用

1. OpenClaw记忆插件memory-lancedb-pro深度解析 在AI助手领域,长期记忆能力一直是提升用户体验的关键。OpenClaw作为新一代智能助手平台,其memory-lancedb-pro插件通过本地向量数据库实现了高效的记忆存储与检索。这个官方插件将记忆数据存储在LanceDB中…

作者头像 李华
网站建设 2026/11/2 10:27:29

Linux无线网络频宽调整与hostapd配置优化

1. Linux无线网络频宽调整的核心价值在Linux环境下调整WLAN频宽(信道宽度)是无线网络优化的关键操作。作为一名长期从事Linux网络管理的工程师,我见过太多因为频宽配置不当导致的性能问题——明明硬件支持802.11n/ac,实测速率却只…

作者头像 李华
网站建设 2026/11/2 10:27:11

企业级IM系统测试实践:从功能到安全的全面验证

1. 项目概述:云间絮语即时通讯系统测试实践"云间絮语"即时通讯系统是一款面向企业级用户的私有化部署通讯解决方案,主打高安全性和低延迟特性。作为测试开发工程师,我们需要在保证基础通讯功能稳定的前提下,特别关注分布…

作者头像 李华