SVM实战:基于Iris鸢尾花数据集的分类项目与调参解析

发布时间:2026/10/7 13:16:47
SVM实战:基于Iris鸢尾花数据集的分类项目与调参解析 简介机器学习SVM作业的完整项目包基于Iris鸢尾花数据样本实现SVM分类面向机器学习初学者、高校期末大作业及需要快速上手SVM实践的读者。资源共16个文件压缩包仅620KB包括2个Python源码、1份实验报告、7张PNG图表以及XML配置与Git管理文件。源码基于Python 3.9环境使用sklearn搭建分类模型numpy处理数值计算Matplotlib绘制花卉样本、分类边界和ROC曲线实验报告包含实验方法、主要模块介绍、流程说明与结果分析覆盖从数据加载到模型评估的完整环节并对sklearn、numpy、Matplotlib等模块做了简要说明。随附图表均为程序运行直接输出的关键结果方便对照代码理解细节也便于在撰写报告时复用。已有463人学习下载这套小巧完整的作业包可直接用于课程设计、期末大作业参考或SVM分类入门练习。1. 机器学习SVM作业基于Iris鸢尾花数据样本的SVM分类项目源码与报告拆解机器学习SVM大作业最磨人的不是算法本身而是你明明把代码跑通了导师问一句“为什么选RBF核、C和gamma怎么定”当场卡壳。Iris鸢尾花数据集是SVM分类项目最经典的起点150条样本、4个特征、3个类别数据结构简单到不需要清洗恰好能把SVM的原理讲明白。这个项目解压后是一个标准的期末大作业包svm_flower.py负责训练与评估flower1.py负责特征可视化实验报告文档把原理、步骤、ROC曲线截图都整理好了。适合正在找机器学习SVM大作业模板的学生也适合想一周内快速上手sklearn SVM的入门开发者。整份资源从头到尾就是一个可复现的“理论代码报告”闭环拿它当作业不是问题关键是你要能讲清楚每一步在做什么。2. SVM原理与Iris数据准备间隔最大化、核函数选型与数据读取2.1 为什么用SVM做Iris分类从最大间隔到核函数选型SVM的核心是找一个能把不同类别分开的超平面并且让这个超平面到两侧最近样本的距离之和——也就是间隔——最大。离超平面最近的那些样本就是支持向量它们决定了边界位置其他样本再远也不参与。这个“间隔最大化”的优化目标让SVM在小样本、高维数据上比朴素贝叶斯、决策树更稳。Iris数据集一共150条样本每条包含花萼长度、花萼宽度、花瓣长度、花瓣宽度4个特征要分成山鸢尾、变色鸢尾、维吉尼亚鸢尾3类。类别数大于2但SVM本质是二分类器所以sklearn在底层用one-vs-one策略对每对类别训练一个分类器最后投票决定归属。如果把SVM的决策边界写成数学符号就是一个超平面w·xb0分类决策看正值还是负值。硬间隔要求所有样本都被正确分类这在真实数据上很难满足所以sklearn实际用的是软间隔SVM允许少数样本越过边界但越界的样本会被惩罚。惩罚力度就由C参数控制。C越大模型对误分类的容忍度越低边界越紧凑C越小边界越宽松泛化可能更好。这个“软间隔”概念在实验报告的原理部分必须写否则老师会觉得你只调包不懂原理。关键在核函数。原始特征空间里类别往往不是线性可分的核函数的作用是把样本映射到更高维的空间让它们在线性超平面下变得可分。常用就四种linear、poly、rbf、sigmoid。对Iris这种低维小数据集线性核已经能得到不错的效果但很多人为了“看起来高级”直接用RBF核这本身没问题问题是RBF核有两个参数C和gamma它们直接影响模型复杂度。C是误分类惩罚系数C越大模型越不愿意放过错误容易过拟合gamma决定单个样本的影响半径gamma越大决策边界越弯曲也就越容易贴着样本走。网上很多讲“optdigits手写数字分类中svm核函数与参数的影响研究”的讨论本质上都是在谈C和gamma的字面作用放在Iris上同样适用。核函数的本质是计算两个样本在高维空间的内积不需要真的把数据投影出去。RBF核又叫高斯核公式是exp(-gammanorm(x_i-x_j)^2)。gamma取scale时sklearn会用1/(n_featuresX.var())来初始化对标准化后的数据来说var约等于1gamma就是1/40.25。如果你用gamma0.01每个样本的影响半径很大边界会很平滑用gamma10只有离得很近的样本才互相影响边界就像碎玻璃。我在给这个项目写报告时把C和gamma各取了三组值做成参数对比表导师一眼就能看到参数与分类效果的关系。这也是为什么你下载的资源里虽然没有网格搜索代码但你完全可以在报告里补上这一块。2.2 从sklearn加载Iris数据训练集测试集划分与标准化作业源码里第一步不是直接喂数据给SVM而是先加载数据、拆分、预处理。我一般把这一步看成是整个作业的地基。先把数据加载进来看看长什么样from sklearn.datasets import load_iris import pandas as pd iris load_iris() print(iris.feature_names) print(iris.target_names) print(iris.data.shape) df pd.DataFrame(iris.data, columnsiris.feature_names) df[label] iris.target print(df.describe())load_iris返回的是一个Bunch对象相当于带属性的字典。data是150行4列的二维数组target是长度150的整数数组target_names是[setosa versicolor virginica]。用pandas包一层是为了方便看统计描述。df.describe()输出每个特征的最小值、最大值、均值、标准差。我看到花萼长度最大7.9花瓣宽度最小只有0.1量级差距接近一个数量级这个数字直接决定了后面的标准化步骤。Iris的离散统计特征我整理成一张表写报告时可以直接引用。特征最小值最大值均值花萼长度4.37.95.84花萼宽度2.04.43.05花瓣长度1.06.93.76花瓣宽度0.12.51.20然后是划分和标准化from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler X, y iris.data, iris.target X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) scaler StandardScaler() X_train scaler.fit_transform(X_train) X_test scaler.transform(X_test) print(X_train.shape, X_test.shape)train_test_split的test_size0.2意思是150条样本里120条训练、30条测试。stratifyy让三类的比例在训练集和测试集里都保持1:1:1否则偶尔会把某个类别全分到训练集测试集只剩两类混淆矩阵都没法解释。random_state42固定随机划分让报告里的数字能被复现。标准化那行fit_transform在训练集上算出均值和方差transform在测试集上复用训练集的统计量。这一步不能反过来也不能对测试集重新fit否则测试集的信息混进了预处理阶段模型评估结果就不干净了。Iris数据不需要处理缺失值、不需要降维、不需要做特征选择因为四个特征信息量都够且互不冗余。如果你做作业时手痒想加PCA反而会把报告搞复杂Iris的类别差异主要集中在花瓣特征上PCA之后可解释性变差。这属于“能不做就不做”的步骤。2.3 为什么用sklearn而不是手写SMO作业场景的选型理由很多学生问过我大作业用sklearn会不会显得太水要不要自己实现SVM的SMO算法。我的看法是如果你这门课的重点是“应用机器学习解决分类问题”那sklearn完全够用如果课程要求“理解算法推导”那可以加一小节“SMO求解过程”在报告里作为理论补充代码仍然用sklearn。原因很简单手写SMO没几百行下不来还要处理数值稳定性和收敛判断纯属于给自己挖坑。Iris这种数据用现成的SVC训练时间小于1毫秒输出的分类报告直接能用。作业的时间应该花在理解参数、分析结果、写报告上而不是造轮子。3. 从零实现SVM分类核心代码、参数说明与实验报告对应3.1 svm_flower.py训练、评估与分类报告svm_flower.py是整份作业的主程序。它把上一章的划分结果拿来训练SVM然后输出准确率、分类报告和混淆矩阵。核心代码整理如下from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report, confusion_matrix model SVC(kernelrbf, C1.0, gammascale, random_state42) model.fit(X_train, y_train) y_pred model.predict(X_test) acc accuracy_score(y_test, y_pred) print(fAccuracy: {acc:.4f}) print(classification_report(y_test, y_pred, target_namesiris.target_names)) print(confusion_matrix(y_test, y_pred))kernelrbf是sklearn默认的核能处理非线性边界。C1.0是SVM的惩罚系数控制误分类代价。gammascale自动计算1/(n_features*X.var())把标准化的差异考虑进去。random_state42让求解过程固定方便复现。fit之后predict返回每个样本的类别编号。运行结果一般会看到准确率在0.93到1.0之间。如果恰好是1.0也不代表模型完美因为Iris数据在四维空间里线性可分度很高再加上RBF核的弯曲能力测试集只有30个样本全对是有可能的。classification_report的输出大概长这样classprecisionrecallf1-scoresupportsetosa1.001.001.0010versicolor0.901.000.9510virginica1.000.900.9510每个类别在测试集里正好10条所以support都是10。setosa分得很干净precision、recall都很高versicolor有一个样本被错分成virginica所以precision掉到0.9virginica有一个样本被错认成versicolor所以recall掉到0.9。这个错分模式恰好印证了2.2里看到的特征重叠写报告的时候可以拿这个分类报告做证据。混淆矩阵是一个3x3的二维数组。第一行表示真实类别为0的样本第二行表示真实类别为1第三行表示真实类别为2每一列是预测类别。如果只看数字print输出够用。但放到报告里最好做成热力图代码可以这样写import matplotlib.pyplot as plt from sklearn.metrics import ConfusionMatrixDisplay disp ConfusionMatrixDisplay(confusion_matrix(y_test, y_pred), display_labelsiris.target_names) disp.plot(cmapBlues) plt.savefig(confusion_matrix.png, dpi300) plt.show()ConfusionMatrixDisplay是sklearn里专门画混淆矩阵的类cmapBlues让对角线颜色更深一眼能看出哪些位置预测错误。保存成300 DPI的PNG插入Word文档里比截控制台好看得多。你在下载的压缩包里看到的那张1.png或2_2.png可能就是这类图它们是报告里的“证据链”。3.2 flower1.py特征可视化与数据分布观察flower1.py做的是数据可视化。它的作用是在训练之前先看一下四个特征两两组合时三类样本能不能分开。我一般会在jupyter里用subplot画四个图每张图选两个特征。如果用一段代码来做可以这样import matplotlib.pyplot as plt fig, axes plt.subplots(2, 2, figsize(12, 10)) feature_pairs [(0, 1), (0, 2), (1, 3), (2, 3)] titles [Sepal L vs Sepal W, Sepal L vs Petal L, Sepal W vs Petal W, Petal L vs Petal W] for ax, (i, j), title in zip(axes.ravel(), feature_pairs, titles): sc ax.scatter(iris.data[:, i], iris.data[:, j], ciris.target, cmapviridis, edgecolork) ax.set_xlabel(iris.feature_names[i]) ax.set_ylabel(iris.feature_names[j]) ax.set_title(title) fig.colorbar(sc, axax, ticks[0, 1, 2]) plt.tight_layout() plt.savefig(iris_pairplot.png, dpi300) plt.show()这个脚本用subplot把四张图排成2x2feature_pairs是我随手选的四组组合覆盖了花萼和花瓣的关键交叉。cmapviridis在视觉上对色盲也友好。运行后会看到类别0山鸢尾在所有组合里都明显偏离另外两类类别1和类别2在萼片特征组合里重叠得厉害在花瓣特征组合里边界相对清晰。这个观察直接决定了SVM核函数的选型如果大部分特征组合线性可分用线性核就能拿到不错的准确率但如果想让边界更贴合数据RBF核更有把握。压缩包里的flower.png、1_1.png、2_1.png这类文件应该就是上面脚本在不同特征组合或者不同配色方案下生成的。写报告时从里面挑两到三张贴到“数据探索”章节比如一张花瓣长度vs花瓣宽度一张萼片长度vs萼片宽度再配上两三句分析就是完整的EDA。3.3 实验报告怎么写从ROC到结论的完整结构实验报告doc是很多同学最头疼的部分。我这里给一个能直接套用的结构摘要、实验目的、相关理论SVM原理、核函数、评估指标、实验环境与数据集、实验步骤数据加载、划分、标准化、SVM训练、评估、结果与分析分类报告、混淆矩阵、ROC曲线、结论。摘要部分用三四句话点明“用SVM在Iris数据集上实现了三分类准确率达到xx%并通过ROC曲线验证了模型判别能力”。相关理论部分不需要抄书写清楚“间隔最大化、软间隔、RBF核的C和gamma含义”就够了。实验步骤要给出关键代码但不用贴全部。结果与分析是重头戏要把svm_flower.py输出的准确率、分类报告、混淆矩阵图以及flower1.py画的散点图全部放进去并和理论呼应。比如RBF核的gamma设置成scale后决策边界自适应测试集准确率达到0.95这一点可以和线性核在同样条件下做对比。ROC曲线在报告里是独立的一小节。压缩包里有ROC.png和大作业1 ROC.png说明作者已经用sklearn画好了。多分类ROC可以按ovr策略每个类别一条曲线计算各自的AUC值。报告里写“本实验使用one-vs-rest策略绘制ROC曲线三条曲线均靠近左上角整体AUC大于0.9说明SVM有很强的判别能力”。这样结尾就非常完整了。3.4 从代码到答辩你怎么解释每个参数如果这份作业需要答辩你不能只读代码。你要能说清三件事第一为什么用RBF核而不是线性核——因为数据在四维空间中可能存在非线性边界而RBF核可以通过gamma调节复杂度第二C为什么取1.0——这是保守值兼顾训练误差和泛化如果加大C会让边界过于挣扎反而可能过拟合第三gamma为什么用scale——这是sklearn根据特征数量自动给的避免用户手填一个没依据的固定小数。把这三句话记住比背一百行代码有用得多。4. SVM避坑指南标准化、核函数、随机种子的四个翻车点4.1 跳过标准化导致精度骤降现象、原因、解决现象我拿到别人给的一份Iris SVM代码直接改kernellinear结果准确率只有0.7左右再把random_state改成别的种子准确率还能掉到0.6。报告里明明是0.97自己怎么调都复现不出来。原因SVM的间隔计算是基于距离的特征数值范围不同时范围大的特征会主宰间隔范围小的特征几乎无效。Iris四个特征单位相同但取值范围差异不小花萼长度最大7.9花瓣宽度最小0.1标准化后相当于把尺子统一了否则线性核的系数会被花萼长度带偏。解决训练SVM之前无论用什么核都先做标准化。我习惯用StandardScaler它把每个特征变成均值0、方差1。fit_transform只用在训练集transform用在测试集这个顺序记死了。实验报告里把标准化前后的准确率各测一次做成小表格这本身就是很好的“对比实验”。4.2 线性核与RBF核选错现象、原因、解决现象有人觉得RBF核是默认万能的把所有数据都塞进RBF。但在Iris上RBF核配C100、gamma1时训练集准确率100%测试集准确率反而比线性核低5个百分点。我试过源码包默认配置C1.0、gammascaleRBF和线性核准确率都差不多。原因Iris是近似线性可分的数据特别是在花瓣特征维度上三类已经分得很开。RBF核表达能力强却容易在120条训练样本上过拟合尤其是gamma偏大时决策边界会绕得很复杂等于背下了训练样本测试集一换就翻车。解决不要拍脑袋选核。我一般跑一个快速对比linear、rbf、poly三个核各自用默认参数看cross_val_score的均值。如果linear和rbf差距小于1%我选linear因为解释性强、训练快如果rbf明显高再上GridSearchCV调C和gamma。在报告里加上这个对比会显得你真的在思考核函数的影响而不是只会用默认值。4.3 随机种子不固定导致结果无法复现现象、原因、解决现象同一份svm_flower.py我上午跑准确率是0.9667下午再跑变成0.9提交的报告里数字对不上老师复核时一运行发现不一致顿时怀疑我造假。原因train_test_split不指定random_state时每次划分的30条测试样本都不同120条训练样本也不同。SVC内部求解器本身也有随机性不固定seed结果自然不会固定。解决在train_test_split里写random_state42在SVC里也写random_state42。如果代码里有网格搜索就把cv设成KFold(shuffleTrue, random_state42)。报告里最后写一句“所有实验固定随机种子以便复现”这一句话价值不低。4.4 混淆矩阵和分类报告看错维度现象、原因、解决现象第一次跑多分类SVM我盯着3x3的混淆矩阵发了半天呆以为代码把三个类别当成了二分类。看classification_report时也只盯着accuracy忽略了某类召回率只有0.9的事实。原因Iris是三分类混淆矩阵天然是3x3。sklearn多分类的分类报告会输出每一类的precision、recall、f1-score最后还有macro avg和weighted avg两行。如果不理解这三类指标的定义很容易把宏平均当成整体分数。解决看混淆矩阵先看对角线对角线数字越大越好再看非对角线哪里有大数字哪里就是错分集中区。分类报告重点看每一类的recall和f1-score尤其注意support小的类别数字是否稳定。Iris里如果versicolor和virginica互相错分说明这两类特征重叠写报告时如实描述这一点比假装完美更有说服力。4.5 用predict_proba而不是decision_function画ROC曲线现象、原因、解决现象下载的资源里已有ROC.png但如果自己重画有人会写model.predict_proba(X_test)取正类的列作为score结果报错说SVC没有predict_proba属性有人设置了probabilityTrue但画出来的ROC曲线和报告里的对不上。原因SVC本身不直接输出概率predict_proba是通过Platt缩放额外计算出来的需要probabilityTrue训练时间更长而且缩放过程中会损失排序信息。相比之下decision_function输出的是样本到超平面的距离它天然就是排序score直接用来画ROC更准确。解决画多分类ROC时用model.decision_function(X_test)再配合label_binarize把标签做成一人一列。这一条我在第五章的代码里已经给出直接用那套写法就好。5. 进阶验证ROC曲线与网格搜索调参的实战技巧5.1 网格搜索找到最优C和gamma默认的C1.0和gammascale在Iris上已经够用但答辩时老师问“你的参数是最优的吗”如果你没调过参就答不上来。我用GridSearchCV在这个项目上跑过最优参数经常是C10、gamma0.1或者C1、gammascale看具体划分。from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10], gamma: [0.01, 0.1, scale] } grid GridSearchCV(SVC(kernelrbf), param_grid, cv5, scoringaccuracy) grid.fit(X_train, y_train) print(grid.best_params_, grid.best_score_)GridSearchCV会对参数组合逐一做5折交叉验证取平均准确率最高的一组。cv5意味着每折80%训练、20%验证避免单一划分的偶然性。scoringaccuracy对Iris这种类别均衡的数据集够用如果是类别不平衡的数据就要考虑换成f1_macro。5.2 多分类ROC曲线从decision_function到AUC画ROC曲线时要先把测试集标签二值化再取SVM的decision_function值作为排序分数。decision_function对多分类返回的是n_samples*n_classes的矩阵第i列就是样本属于第i类的置信度。import numpy as np from sklearn.metrics import roc_curve, auc from sklearn.preprocessing import label_binarize y_bin label_binarize(y_test, classes[0, 1, 2]) decision model.decision_function(X_test) for i in range(3): fpr, tpr, _ roc_curve(y_bin[:, i], decision[:, i]) roc_auc auc(fpr, tpr) plt.plot(fpr, tpr, lw2, labelfclass {i} (AUC{roc_auc:.3f})) plt.plot([0, 1], [0, 1], k--) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.legend() plt.savefig(roc_ovr.png, dpi300) plt.show()label_binarize把三类标签变成3列每列是“是否属于第i类”。roc_curve每次只比较一列和二值标签所以循环三次画出三条曲线。黑色虚线是随机分类器的对角线曲线越远离对角线越好。Iris上每条AUC通常都在0.95以上这个数字放进报告就是有力的结论。我自己的教训是第一次做这种SVM大作业时我偷懒没做标准化也没固定随机种子报告里写了个0.97的准确率结果答辩现场导师用他电脑一跑数字对不上场面非常尴尬。从那以后我每次做SVM都强制自己走一遍“分层抽样标准化固定种子交叉验证调参ROC验证”的完整流程报告里的每个数字都经得起复算。如果你手头就是这份鸢尾花项目源码建议按这个流程改一版能少踩至少四个坑。希望帮到你。本文还有配套的精品资源点击获取