简介这是一份面向机器学习课程期末大作业的SVM分类项目资源基于经典的Iris鸢尾花数据集提供完整Python源码与配套实验报告。代码基于Python 3.9 IDLE开发整合sklearn、numpy、matplotlib等模块覆盖数据读取、标准化、SVM建模、核函数对比和结果可视化全流程适合初学机器学习、需要完成SVM作业或想快速搭建分类实验的学生参考。资源包共16个文件含2个Python脚本、1份doc实验报告、7张结果图包括ROC曲线及分类边界可视化以及若干项目配置文件整体620KB轻量且目录清晰。源码不仅包含SVM训练与评估逻辑还提供花瓣、花萼等特征分布的绘制代码便于直观理解数据与模型表现实验报告则系统讲解SVM原理、参数调优和结果分析可直接作为大作业文档框架参考。已有463人学习/下载整体完成度和说明清晰度较高适合期末大作业复用与课程设计借鉴。 期末作业撞上SVM一份Iris鸢尾花源码包能帮你少熬两个通宵做过机器学习期末大作业的人都知道选题最怕的不是不会写是写到一半发现代码跑不出图、报告凑不满页。这次拆的这份基于Iris鸢尾花数据样本的SVM分类项目解压之后是一个完整的作业包——两个Python脚本svm_flower.py和flower1.py、一份已经排好版的实验报告、还有散点图、决策边界图和ROC曲线图。它的价值在于环境要求极低Python 3.9的IDLE加上sklearn、numpy、matplotlib三个库就能跑数据直接用sklearn内置的Iris数据集不需要额外找数据文件。适合谁正在选机器学习期末选题、或者想快速吃透SVM在真实数据上怎么落地的学生。下面我会把原包里的代码逻辑拆开讲包括每个参数为什么这么设以及写报告时最容易翻车的几个点。从最大间隔到核函数SVM为什么能在Iris上直接见效2.1 硬间隔、软间隔与支持向量先想清楚SVM在算什么SVM的核心不是“画一条线”而是“画一条离两类样本都足够远的线”。这条线在二维里是直线在四维的Iris特征空间里就是一个超平面。那些离超平面最近的样本点决定了超平面最终落在哪它们就是支持向量。整个模型的训练过程本质上就是在“让间隔尽量大”和“让分类错误尽量少”之间做权衡。Iris数据集150个样本、4维特征、3个类别本质上是一个软间隔优化问题。三类鸢尾花里Setosa和另外两类分得很开但Versicolor和Virginica在sepal维度上有明显重叠。SVM用hinge损失加正则项来平衡“分对更多样本”和“间隔尽量宽”这两个目标C参数就是这两个目标的权重。C越大模型越偏向分对训练集里的所有点代价是间隔变窄、过拟合风险升高C越小间隔越宽对误分类的容忍度也越高。这里顺带说一个选型问题为什么这个场景不用CNN。因为Iris是结构化表格数据样本量只有150个、特征只有4维SVM直接在低维空间找超平面就够用了。CNN的优势在于自动学特征表示但那是给图像、文本这类高维非结构化数据用的拿CNN来跑150条表格数据不仅没有优势反而会因为数据量太小而严重过拟合。这也和很多人初学时的困惑一致SVM和CNN原理不同适用的数据形态完全不同不是谁替代谁的关系。核函数的选择同样关键。svm_flower.py这个项目默认走RBF径向基核因为Iris的数据并不是严格线性可分的Versicolor和Virginica两类在部分特征维度上有交错。RBF核能把样本映射到高维空间再找超平面实际效果通常好于线性核。但对应的代价是多了个gamma参数gamma控制单个样本的影响半径gamma太小决策边界过于平滑容易欠拟合gamma太大边界会围着每个样本画圈直接过拟合。对Iris这种小样本gamma取默认值通常够用但要想在报告里展示调参过程就得手动遍历C和gamma的组合。对比项线性核 LinearSVCRBF核 SVC(kernelrbf)假设原始特征空间线性可分允许非线性映射到高维参数只有CC gamma计算开销低中等在Iris上的测试精度通常0.90~0.96通常0.93~0.98报告亮点参数少解释简单可以讲核技巧能展开调参分析我在实际跑这个项目时会给两种核各跑一遍然后做个对比表放进报告。导师会觉得你在选型上花过心思这也是原包里既有svm_flower.py又有flower1.py的可能原因——两个脚本各承担一种实验对比。2.2 Iris数据集为什么“看着简单、写报告不简单”Iris的三个类别是Setosa、Versicolor、Virginica每类50个样本共150行数据特征就4个sepal length、sepal width、petal length、petal width。用sklearn自带的load_iris()加载后data是(150,4)的ndarraytarget是(150,)的整数标签0/1/2分别对应三个类别。特征取值范围(cm)类别区分度sepal length4.3~7.9中等三个类分布有重叠sepal width2.0~4.4较差Versicolor与Virginica混在一起petal length1.0~6.9很好Setosa明显分离petal width0.1~2.5很好是关键判别特征写实验报告最容易犯的一个错是把150个样本全部拿去训练然后拿同一个数据集再算准确率——那是自欺欺人。正确做法是划分训练集和测试集。这个项目用的是sklearn的train_test_split加stratify参数按类别比例分层抽样保证每个类别在训练集和测试集里的比例都和原始数据一致。样本量本来就小如果shuffle之后碰巧把某一类全划进训练集报告里的准确率会严重失真。另一个值得写进报告的观察点是petal length和petal width这两个特征本身就足以把三类分开因此做二维散点图时优先选这两个维度而不是sepal的两个维度。这个选择会直接影响可视化效果后面第4章会专门演示。复现svm_flower.py数据加载、特征标准化与分类报告全流程3.1 加载Iris并划分训练集stratify、random_state与特征标准化原包里svm_flower.py的第一段逻辑基本就是标准的数据加载与划分流程。需要注意一个细节SVM的RBF核依赖样本间的距离计算如果某个特征量纲特别大它会主导距离其他特征就失效了。Iris四个特征的量纲都在厘米级别差异不大但为了流程规范我还是建议加上标准化。from sklearn.datasets import load_iris from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler # 加载sklearn内置的鸢尾花数据集 iris load_iris() X, y iris.data, iris.target # 标准化的常见做法先fit训练集再transform测试集 scaler StandardScaler() X scaler.fit_transform(X) # 划分训练集与测试集测试集占30% X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, stratifyy, random_state42 ) print(训练集样本数:, X_train.shape[0]) print(测试集样本数:, X_test.shape[0])逻辑说明load_iris()返回的是Bunch对象里面同时包含data、target、feature_names和target_names不需要自己读CSV文件。train_test_split把150个样本切成105训练、45测试stratifyy保证三类在两边都保持相同的比例random_state42让每次运行结果完全一致。StandardScaler先在整个数据集上fit再transform目的是让每个特征都变成均值为0、方差为1的分布。参数说明test_size0.3是常见划分比例样本量小的时候也可以用0.2但0.3会让测试集有45个样本评估指标更稳。random_state42只是固定随机种子的约定值取多少都行但一旦定了就不能改否则报告里的数字又要重跑。stratify只有在分类问题里才需要回归问题不需要。3.2 训练SVC并评估默认参数下的基础结果接着往下就是训练和评估部分。SVC默认核函数是rbf默认C1.0、gammascale对Iris数据集来说直接跑出来的测试精度通常在0.95左右已经足够写进报告。from sklearn.svm import SVC from sklearn.metrics import classification_report, accuracy_score # 创建RBF核的SVM分类器 model SVC(kernelrbf, C1.0, gammascale, random_state42) # 在训练集上拟合 model.fit(X_train, y_train) # 预测测试集并输出评估指标 y_pred model.predict(X_test) print(测试集准确率: {:.4f}.format(accuracy_score(y_test, y_pred))) print(classification_report(y_test, y_pred, target_namesiris.target_names))逻辑说明SVC的训练分两步fit负责寻找支持向量和超平面参数predict拿训练好的模型去预测新样本的类别。classification_report会输出每个类别的precision、recall、f1-score和support这是报告里最能体现评估分析深度的数据。参数说明C1.0是SVM默认的软间隔惩罚系数Iris样本量小、特征维度低不需要调大C去强行拟合gammascale是sklearn的默认策略会根据特征数量自动计算gamma1/(n_features * X.var())对4维特征来说算出来的值比较适中。如果你把这个项目里的kernel改成linear训练代码完全不用动可以顺手做核函数对比实验。3.3 项目里的两份脚本怎么分工svm_flower.py与flower1.py原包解压后有两个Python文件从命名和配套图片推断svm_flower.py是完整版主流程flower1.py更像是一个可视化辅助脚本或者简化版本。我一般会这样组织实验目录svm_flower.py负责训练、评估和输出classification_reportflower1.py负责读取同一份数据画散点图、决策边界图最后在报告里用svm_flower.py的结果数据用flower1.py的图当可视化证据。这样的分工有个实际好处训练和画图解耦。调参时只需要改svm_flower.py里的参数再跑一遍不需要重新生成所有图。项目里的1_1.png、1_2.png、2_1.png、2_2.png就是这两个脚本分别产出的图对应不同特征组合和不同核函数的输出结果。如果你想在这个基础上改成自己的作业保持这个“训练脚本可视化脚本”的目录结构后面补实验、换数据都会省很多事。把实验结果变成报告素材散点图、决策边界与多分类ROC4.1 特征散点图做出“肉眼可见的分类效果”散点图是报告的第一张图作用是展示原始数据的分布。关键在于选哪两个特征来画。之前讲过petal length和petal width的区分度远高于sepal的两个维度。import matplotlib.pyplot as plt # 取petal length和petal width两个特征画散点图 plt.figure(figsize(8, 6)) colors [red, green, blue] labels iris.target_names for i in range(3): idx y i plt.scatter(X[idx, 2], X[idx, 3], ccolors[i], labellabels[i], edgecolork, s50) plt.xlabel(Petal Length (cm)) plt.ylabel(Petal Width (cm)) plt.title(Iris Data Distribution by Petal Features) plt.legend() plt.savefig(flower.png, dpi150) plt.show()逻辑说明X[idx, 2]取的是第3个特征petal lengthX[idx, 3]取第4个特征petal widthidx是按类别生成的布尔索引三类样本依次用不同颜色画出。保存时把dpi设成150放到Word里不会糊。如果你拿sepal length和sepal width画同一张图会看到Versicolor和Virginica基本叠在一起给人“这个数据集很难分”的错觉。用petal画则是三类清晰分开和后面的分类准确率互相印证。报告里图与数据保持一致答辩时会更有说服力。4.2 决策边界二维可视化只能做投影示意别把它当真实边界SVM在4维空间里的真实决策边界是个三维超平面二维画图只能选两个特征做切片投影。常见做法是生成网格点把网格点送入模型预测再用等高线把预测结果画出来。import numpy as np from matplotlib.colors import ListedColormap def plot_decision_boundary(model, X, y, feature_idx(2, 3)): x0_min, x0_max X[:, feature_idx[0]].min() - 0.5, X[:, feature_idx[0]].max() 0.5 x1_min, x1_max X[:, feature_idx[1]].min() - 0.5, X[:, feature_idx[1]].max() 0.5 # 生成网格点步长0.02用于画平滑边界 xx, yy np.meshgrid( np.arange(x0_min, x0_max, 0.02), np.arange(x1_min, x1_max, 0.02) ) # 构造二维特征矩阵并预测 Z model.predict(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) # 绘制等高线填色图 plt.contourf(xx, yy, Z, alpha0.3, cmapListedColormap([red, green, blue])) plt.scatter(X[:, feature_idx[0]], X[:, feature_idx[1]], cy, edgecolork, s40) plt.xlabel(Feature str(feature_idx[0])) plt.ylabel(Feature str(feature_idx[1])) plt.savefig(decision_boundary.png, dpi150) plt.show()注意这里有一个隐藏的坑训练模型用的是4维特征画图只给2个维度的输入np.c_[xx.ravel(), yy.ravel()]构造出的矩阵只有2列模型会直接报维度不匹配。解决办法是训练时单独用一个2维特征的SVM专门做可视化或者把网格点补成4维、未画的两个特征统一填训练集均值。原包里2_1.png、2_2.png这类图大概率是单独训练了一个2维SVM来画的。报告里最好加一句“图中决策边界基于两个特征的可视化投影与完整四维模型存在差异”这句话能挡住答辩时的很多追问。4.3 ROC曲线与多分类处理报告里的硬通货原包里有一张ROC图说明作者把ROC曲线当成了报告的加分项。二分类的ROC大家都会画但Iris是三分类sklearn的roc_auc_score默认只支持二分类需要多走一步。from sklearn.metrics import roc_curve, auc from sklearn.preprocessing import label_binarize # 将三分类标签转为二分类形式每一列代表“是否属于某一类” y_test_bin label_binarize(y_test, classes[0, 1, 2]) # 获取每个类别的决策函数值 y_score model.decision_function(X_test) plt.figure(figsize(8, 6)) for i in range(3): fpr, tpr, _ roc_curve(y_test_bin[:, i], y_score[:, i]) roc_auc auc(fpr, tpr) plt.plot(fpr, tpr, label{} (AUC{:.3f}).format(iris.target_names[i], roc_auc)) plt.plot([0, 1], [0, 1], k--, labelChance Level) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.title(Multi-class ROC Curves (One-vs-Rest)) plt.legend() plt.savefig(roc_curve.png, dpi150) plt.show()逻辑说明多分类ROC用的是One-vs-Rest策略把三分类拆成三个二分类问题每个类别算一条ROC曲线。label_binarize把[0,1,2]的标签变成三列01矩阵decision_function返回的是每个样本到各分类超平面的距离距离越大表示模型越确信属于这一类别。参数说明y_score[:, i]取第i类对应的决策值和y_test_bin[:, i]一一对应。虚线是随机分类器的基准线AUC比0.5高得越多说明模型越有效。Iris数据集上三类AUC基本都在0.97以上这张图放进报告比单贴一个accuracy有说服力得多。如果换成ovr策略的predict_proba也能得到概率值但SVC的predict_proba本身是依赖Platt缩放计算的在小型数据集上不如decision_function直观。避坑清单用Iris做SVM的五个翻车现场与排查方法5.1 同一份代码每次跑出来的准确率都不一样现象不改任何代码重复运行svm_flower.py测试集准确率一次是0.933一次是0.978报告里的数字不知道该填哪个。原因train_test_split没有固定random_state每次运行都会重新随机划分数据集测试集换了准确率自然跟着变。解决在train_test_split和SVC里都固定random_state42同时带上stratifyy保证划分结果和类别比例都稳定。我现在的习惯是写完代码先检查随机种子有没有固定再谈跑实验。5.2 用训练集测出来的准确率是0.98测试集只有0.85现象把全部150条数据拟合模型后回测准确率接近满分但划分出测试集再测掉到0.85。原因模型在训练集上过拟合了。这种情况常见于gamma调得过大RBF核的决策边界围着训练样本画圈泛化能力变差。解决训练集和测试集严格分离报告里只报测试集指标。如果测试集掉得厉害把gamma往小了调比如从默认的scale改成0.01、0.1这样显式的值再观察准确率变化。5.3 画决策边界时报维度不匹配错误现象训练好的4维SVM拿两个特征的网格点去predict直接报shape mismatch错误。原因模型的n_features_in_是4传入的网格矩阵只有2列sklearn会检查特征数并拒绝预测。解决两个方案二选一。要么再训练一个只用两个petal特征的SVM专门用于可视化要么在画图时把网格点补成4列另外两列填训练集均值。我一般推荐前者因为训练2维模型只要一行代码可视化语义也更清晰。但要在报告里注明这是二维投影模型不能代表四维分类器的真实边界。5.4 IDLE环境里plt.show()卡死窗口现象在IDLE的shell里跑带plt.show()的脚本图像窗口弹出来但shell卡住不动关掉窗口代码才继续执行。原因plt.show()默认是阻塞式的。在IDLE这种交互式环境下事件循环没有被完全托管表现就是窗口不响应。解决脚本里先plt.savefig()保存图片再用plt.show()做交互查看或者提交作业时干脆只保留savefig去掉show。项目里的png文件都是savefig的产物用保存的图片文件放进报告清晰度比截图高一档。5.5 报告里只有准确率没有分类报告和ROC答辩被问“怎么证明模型不是蒙对的”现象accuracy_score输出一个0.95就结束了报告里就一行字描述结果被追问时答不上来。原因评估维度太单薄。三分类数据只看整体准确率看不出每个类别各自的区分情况。解决把classification_report里每一类的precision、recall、f1都贴进报告再补一张多分类ROC图。Iris这份数据集三个类别的support都是15左右指标本身有意义的比单独一个准确率有说服力得多。进阶技巧用网格搜索把C和gamma写成报告里的实验分析很多人的报告写到“模型准确率为0.95”就结束了但高分作业通常会多走一步做一次参数搜索实验展示C和gamma对结果的影响。下面是给原项目补上网格搜索的最小改动。from sklearn.model_selection import GridSearchCV from sklearn.svm import SVC # 定义参数搜索范围C和gamma各取四个值 param_grid { C: [0.1, 1, 10, 100], gamma: [0.01, 0.1, 1, 10] } # 用5折交叉验证评估每组参数 grid_search GridSearchCV( SVC(kernelrbf), param_grid, cv5, scoringaccuracy ) grid_search.fit(X_train, y_train) print(最佳参数:, grid_search.best_params_) print(交叉验证最佳得分: {:.4f}.format(grid_search.best_score_)) best_model grid_search.best_estimator_ test_acc accuracy_score(y_test, best_model.predict(X_test)) print(最优模型在测试集上的准确率: {:.4f}.format(test_acc))GridSearchCV会遍历16组C和gamma的组合每组用5折交叉验证评估最后返回交叉验证得分最高的参数组合。best_estimator_是用选中参数在全部训练集上重新拟合的模型可以直接拿去测测试集。C取0.1到100跨了三个数量级覆盖从强正则到弱正则的范围gamma取0.01到10同理。在这份Iris数据上最优参数通常落在C1或C10、gamma0.1或1附近交叉验证得分在0.95以上。如果最优组合落在搜索范围的边界说明范围不够还要往外扩一层再搜。拿到网格搜索结果后再做一张小表格放进报告的“实验结果与分析”小节表头是三列参数组合、5折交叉验证得分、测试集准确率。只列最优的3到5组不用全部16组。写讨论时对照表格说一句“当C增大时模型更注重拟合训练集交叉验证得分先升后降说明软间隔惩罚系数存在一个合适区间”这一句比任何现成结论都更能体现实验是你亲手做的。我在最后一次交作业时就是把这套资源里的默认SVC换成GridSearchCV版本把搜索结果和ROC图一起贴进报告答辩被问到“为什么选RBF核”和“参数怎么确定”时都能直接指着表格回答。从那以后我每次跑SVM实验都强制走一遍这个流程先固定随机种子再跑默认参数拿基线然后开网格搜索找最优参数最后把参数表和ROC图一起存进报告素材文件夹整个流程下来顺了很多希望帮到你。本文还有配套的精品资源点击获取