
简介一份面向机器学习初学者的SVM分类实战作业包基于经典Iris鸢尾花数据集完成支持向量机建模与实验分析适合Python机器学习课程作业、期末复习或入门实践。资源内含完整Python源码与实验报告使用Python 3.9及sklearn、numpy实现数据加载、模型训练、参数调优与可视化并配套ROC曲线、分类结果图等多张图片便于对照理解SVM原理和评估方法。压缩包共16个文件包括2个py脚本、1份docx报告、7张png图片以及若干xml配置整体仅611KB轻量便于下载学习。已有990人学习可作为同类作业的参考模板与排错思路来源。通过源码阅读可掌握sklearn中SVM的使用流程、核函数选择与结果可视化结合报告能快速梳理实验步骤适合需要提交完整作业或想系统理解鸢尾花分类案例的读者。1. 这个作业真正要你掌握的SVM Iris 的最小闭环SVM 作业在机器学习课程里出现频率极高但大多数同学卡住的点并不是算法推导而是「源代码能跑但不知道怎么解释」和「实验报告一问三不知」这两件事。Iris 鸢尾花数据集作为 SVM 分类的经典入门对象本身只有 150 条样本、4 个特征、3 个类别训练起来几秒钟就能出结果这反而让作业重心落到模型理解而不是调参技巧上。这篇内容围绕「Python 机器学习 SVM 作业源码 实验报告」这条线展开先给你一套能直接在本机跑通的 SVM 分类源码再拆解 C、gamma、核函数这几个 SVM 核心参数在 Iris 上的实际影响最后补上一份可复现的实验报告写作框架。适合正在做 SVM 作业、或者想系统梳理支持向量机分类流程的读者。2. 用 scikit-learn 跑通 Iris SVM 的基线模型2.1 为什么选 Iris 数据集做 SVM 入门Iris 数据集是机器学习里最常被当作「第一个分类任务」的数据集合原因有三个一是样本量小150 条数据足够让 SVM 在普通笔记本上秒级训练完成不需要 GPU 也无需分布式环境二是特征维度低只有花萼长度、花萼宽度、花瓣长度、花瓣宽度四个连续数值特征不需要做复杂的特征工程三是类别边界有明显可分性其中 setosa 类与另外两类线性可分而 versicolor 和 virginica 之间存在少量重叠刚好能展示 SVM 核函数和软间隔的作用。选 Iris 做 SVM 作业的另一个理由是它天然适合对照实验。你可以很轻松地比较线性核与 RBF 核的效果也可以在固定核函数的情况下调节惩罚系数 C观察过拟合和欠拟合的信号。从作业评分角度看Iris 数据本身不构成技术难点真正拉开差距的是你能否把 SVM 的参数含义讲清楚并用实验数据佐证你的说法。所以后面所有代码都围绕「基线模型 调参 可视化 结论」这一套标准流程来组织。2.2 数据加载与训练/测试划分的标准化写法2.2.1 加载并查看数据结构在 Python 环境中最省事的方案是用 scikit-learn 自带的加载函数它直接返回 NumPy 数组和类别名称省去从 CSV 读取时的路径问题。下面是完整的载入和查看代码import numpy as np import pandas as pd from sklearn.datasets import load_iris # 加载鸢尾花数据集 iris load_iris() X iris.data # 特征矩阵形状 (150, 4) y iris.target # 标签向量形状 (150,) # 转成 DataFrame 方便查看数据概貌 df pd.DataFrame(X, columnsiris.feature_names) df[label] y print(df.head(10)) print(特征名:, iris.feature_names) print(类别名:, iris.target_names) print(样本量:, X.shape[0], 特征数:, X.shape[1])这段代码做了三件基础事把数据加载到内存把特征矩阵和标签分离再用 pandas 快速预览数据分布。输出中特征名是四个花部测量值类别名对应三个鸢尾花品种。我习惯先看df.info()或df.describe()确认没有空值和量纲异常再进入建模环节。Iris 数据本身已经是 float 格式没有缺失值所以载入后可以直接使用。2.2.2 划分训练集和测试集时容易忽略的随机种子训练与测试划分看起来只是两行代码的事但随机种子不固定会导致每次跑出来的结果都不一样这在作业报告里是很扣分的点。正确的写法是显式声明random_state保证实验结果可复现。from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, # 测试集占 30% random_state42, # 固定随机种子结果可复现 stratifyy # 按类别比例分层采样 ) print(训练集大小:, X_train.shape) print(测试集大小:, X_test.shape) print(训练集类别分布:, np.bincount(y_train)) print(测试集类别分布:, np.bincount(y_test))这里三个参数值得注意。test_size0.3表示留出 30% 数据做测试如果你想要更大的训练集可以改成 0.2random_state42是一个约定俗成的种子值固定后每次划分相同stratifyy是分层采样让训练集和测试集里三个类别的比例与原始数据一致。Iris 数据集本身类别均衡分层采样在这类小数据集上特别重要否则极端情况下测试集可能只有两个类别准确率曲线会失真。2.3 线性 SVM 的 3 行核心代码与参数说明先用最简单的线性核 SVM 建立基线scikit-learn 的SVC类一行就能完成训练和预测from sklearn.svm import SVC from sklearn.metrics import accuracy_score # 创建线性 SVM 分类器 svm_linear SVC(kernellinear, C1.0, random_state42) # 在训练集上拟合模型 svm_linear.fit(X_train, y_train) # 预测测试集并计算准确率 y_pred svm_linear.predict(X_test) print(线性 SVM 准确率:, accuracy_score(y_test, y_pred))代码里的三个参数是作业报告里必须解释的部分。kernellinear表示使用线性核也就是不把特征映射到高维空间直接求原始空间里的最大间隔超平面C1.0是软间隔惩罚系数控制误分类样本的容忍度C 越大越不允许训练集出错C 越小则间隔更宽但对误分类更宽容random_state42只影响随机数生成对线性 SVM 的确定性求解影响不大但保留它是好习惯。这里有个常见的认知误区线性 SVM 在 Iris 上准确率也能到 90% 左右但把测试集换成只保留花瓣长度和花瓣宽度两个特征时效果会略降。原因是 setosa 类别线性可分但其他两类存在重叠区域单纯线性超平面很难同时兼顾。这个现象是第 3 章引入核函数和调参的动机。提示SVC默认使用 RBF 核如果创建模型时不写kernellinear你其实训练的是非线性 SVM。做基线对比时一定要明确写出核类型。2.4 用混淆矩阵和分类报告评估基线模型准确率是一个过于粗糙的指标尤其在 Iris 这种小样本数据集上一个类别全对、另外两个类别混在一起时准确率依然可能维持在很高水平。为了在实验报告里更专业地展示结果我会同时输出混淆矩阵和 per-class 的精确率、召回率。from sklearn.metrics import confusion_matrix, classification_report # 计算混淆矩阵 cm confusion_matrix(y_test, y_pred) print(混淆矩阵:) print(cm) # 输出每个类别的精确率、召回率和 F1 print(\n分类报告:) print(classification_report(y_test, y_pred, target_namesiris.target_names))混淆矩阵的行代表真实类别列代表预测类别。以cm[0, 0]为例它表示真实为 setosa 且被预测为 setosa 的样本数cm[1, 2]表示真实为 versicolor 但被误判为 virginica 的样本数。分类报告里每一行对应一个类别precision表示预测为该类别的样本中真正属于该类别的比例recall表示真实为该类别的样本中被正确识别的比例f1-score是两者的调和平均。运行上面代码后你大概率会看到 versicolor 和 virginica 之间有少量互相误判的情况。这不是代码错误而是数据本身的客观现象。在实验报告里这个结果可以写成「线性 SVM 对 setosa 类完全可分对重叠区域的 versicolor/virginica 存在混淆」为下一步调参提供依据。3. 核函数与 C 值Iris 上 SVM 的真正调参点3.1 线性核 vs RBF 核在 Iris 上的表现差异线性核把数据当作在原始特征空间里线性划分。Iris 数据在四个特征的全空间下线性核能取得不错效果但如果你把数据降到两个特征再画图会发现 versicolor 和 virginica 并非严格线性可分。这时 RBF 核的优势就体现出来它通过高斯径向基函数把样本映射到无限维特征空间在原始空间中表现为用非线性边界分割数据。我一般会让两组模型跑同一个测试集然后记录准确率和训练时间。RBF 核在 Iris 上往往比线性核高几个百分点而且需要指定额外参数gamma。这里有一个很容易被作业扣分的地方RBF 核有两个超参 C 和 gamma两个参数相互影响不能简单地「默认参数就完事」。下面这段代码展示两种核的快速对比# 对比线性核与 RBF 核在相同训练测试划分下的效果 kernels [linear, rbf] for k in kernels: model SVC(kernelk, C1.0, random_state42) model.fit(X_train, y_train) acc model.score(X_test, y_test) print(fkernel{k:8s}, 测试集准确率 {acc:.4f})输出会显示 RBF 核的准确率不低于线性核但这不代表可以盲目使用 RBF。在实验报告里你应该把「线性核在低维特征上可解释性强、RBF 核更适合非线性边界」这句话放在结果分析部分并跟表格里的数据对照。3.2 C 值与 gamma 的直观含义和数值范围C 值是 SVM 的软间隔参数它控制着「违反间隔的代价」。C 值小模型更注重得到更宽的分类间隔可能容忍更多训练集误分类C 值大模型会尽量把所有训练样本都分类正确但间隔变窄容易出现过拟合。在 Iris 上C 从 0.01 变到 100 时训练集和测试集准确率会出现明显变化。gamma 参数只存在于核函数中。对 RBF 核来说gamma 决定了单个训练样本的影响力半径。gamma 越小决策边界越平滑可能导致欠拟合gamma 越大每个样本的影响范围越小决策边界越复杂容易围绕单个样本画出小圈子直接导致过拟合。经验上gamma 的常用搜索范围是[0.001, 0.01, 0.1, 1, 10]C 的常用搜索范围是[0.01, 0.1, 1, 10, 100]。为了直观理解四组参数组合的效果可以在作业中用交叉验证的方式记录训练准确率、测试准确率和支持向量数量。支持向量数量也是一个值得写进报告的信息C 增大或 gamma 增大时支持向量数量通常会减少说明模型对边界附近的样本更敏感。3.3 用网格搜索 GridSearchCV 一次性得到最优参数手动组合 C 和 gamma 很浪费时间scikit-learn 提供了GridSearchCV来帮你遍历参数组合并用交叉验证自动选出最优参数。这里我用一个参数网格做示范输出结果会打印出最优参数和交叉验证得分。from sklearn.model_selection import GridSearchCV # 定义待搜索的参数网格 param_grid { C: [0.01, 0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1, 10], kernel: [rbf] } # 创建网格搜索对象 grid GridSearchCV( SVC(random_state42), param_grid, cv5, # 5 折交叉验证 scoringaccuracy, n_jobs-1 # 使用所有 CPU 核 ) # 在训练集上拟合 grid.fit(X_train, y_train) # 输出最优参数与得分 print(最优参数:, grid.best_params_) print(最优交叉验证准确率:, grid.best_score_) print(测试集准确率:, grid.score(X_test, y_test))GridSearchCV的核心机制是把训练集再分成 5 份轮流用 4 份训练、1 份验证循环 5 次后取平均准确率作为当前参数组合的评分。cv5表示这个交叉验证轮数scoringaccuracy指定评分函数n_jobs-1让搜索过程并行运行。在 Iris 这种小数据上整个搜索几秒内就能完成。运行后得到的最优参数常常是C1附近、gamma0.1左右。这里要提醒一点GridSearchCV只用训练集做交叉验证最优参数确定后再去预测测试集这个顺序不能颠倒。如果你先看测试集结果再回头调整参数就相当于把测试集泄漏进了训练过程会导致实验报告的结论不可信。网格搜索输出的最优参数和手动尝试的结果有差异是正常的因为交叉验证是在训练集内部打分而最终测试集准确率是另一回事。下面是一个典型的结果表格可以直接用在实验报告的「参数对比」小节里参数组合Cgamma训练准确率交叉验证得分测试准确率线性核基线1.0-0.980.940.93RBF 默认1.0auto0.980.950.95RBF 最优1.00.10.990.960.96RBF 过拟合100101.000.900.88注意最后一行当C100、gamma10时训练准确率冲到 1.0但交叉验证和测试准确率反而下降这是过拟合的典型信号。实验报告里用这个现象来论证「SVM 参数不是越极端越好」会非常有说服力。4. 可视化决策边界与支持向量的作用4.1 为什么只取两个特征画二维决策边界原始 Iris 数据有 4 维特征人眼无法直接观察高维空间里的超平面所以作业要求里常见的做法是选取两个特征做二维可视化。这不算降维分析而是为了把 SVM 的决策边界「画出来」。sklearn 支持向量机本身是针对完整特征训练的如果你想在二维图上看到边界就必须用同样的训练数据但只取两列重新训练模型或者把画图用的特征空间限定为两个维度。很多同学会把「四特征训练 两特征画图」混在一起导致图形与模型不一致。正确的做法是明确说明可视化模型只用了哪两个特征并注明这是为了展示决策几何而非最佳分类性能。通常我会选择花瓣长度和花瓣宽度因为这两个特征在原始数据中区分度最高画出来的分类边界最直观。4.2 用 meshgrid 生成二维决策边界的完整代码下面的代码会用花瓣长度第 2 列和花瓣宽度第 3 列训练一个 RBF 核 SVM然后绘制出每个区域对应的类别颜色和决策边界。import matplotlib.pyplot as plt from matplotlib.colors import ListedColormap from sklearn.svm import SVC # 只取两个特征用于可视化 X_two X[:, [2, 3]] # 花瓣长度、花瓣宽度 X_train2, X_test2, y_train2, y_test2 train_test_split( X_two, y, test_size0.3, random_state42, stratifyy ) # 训练 RBF 核 SVM参数用上一章搜索得到的较优值 clf SVC(kernelrbf, C1.0, gamma0.1, random_state42) clf.fit(X_train2, y_train2) # 生成坐标网格 x_min, x_max X_two[:, 0].min() - 0.5, X_two[:, 0].max() 0.5 y_min, y_max X_two[:, 1].min() - 0.5, X_two[:, 1].max() 0.5 xx, yy np.meshgrid( np.linspace(x_min, x_max, 200), np.linspace(y_min, y_max, 200) ) # 预测每个网格点的类别 Z clf.predict(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) # 绘制填充等高线图 colors [lightcoral, lightgreen, lightblue] cmap ListedColormap(colors) plt.contourf(xx, yy, Z, levels[-0.5, 0.5, 1.5, 2.5], cmapcmap, alpha0.6) plt.scatter(X_train2[:, 0], X_train2[:, 1], cy_train2, cmapListedColormap([red, darkgreen, blue]), edgecolork, s40) plt.xlabel(petal length (cm)) plt.ylabel(petal width (cm)) plt.title(SVM RBF kernel decision boundary on Iris (2 features)) plt.show()这段代码里np.linspace(x_min, x_max, 200)生成了每个坐标轴上的 200 个点组合成 200x200 的网格clf.predict对这些网格点逐个分类得到的Z再按网格形状还原。contourf用填充颜色的方式把不同类别区域画出来等高线层级用[-0.5, 0.5, 1.5, 2.5]把三个类别的预测值分隔开。plt.scatter把训练样本画在最上层方便观察哪些点落在错误区域。当你运行这段代码会看到边界的弯曲集中在 versicolor 和 virginica 的接壤地带而 setosa 区域非常干净。这就是 RBF 核在局部非线性区域发挥作用的表现。4.3 支持向量的可视化与物理含义SVM 与其他分类器最大的区别是决策面只由支持向量决定。scikit-learn 训练后的SVC对象里有support_vectors_属性保存了所有支持向量的坐标。我在作业报告里会特别画一张图用不同的标记把支持向量圈出来。# 用上一节训练好的 clf 继续画图 plt.figure(figsize(8, 6)) # 重新画一遍样本散点但这次用不同颜色标记支持向量 plt.scatter(X_train2[:, 0], X_train2[:, 1], cy_train2, cmapListedColormap([red, darkgreen, blue]), edgecolork, s40, labeltraining samples) # 支持向量用大号空心圈标记 sv clf.support_vectors_ plt.scatter(sv[:, 0], sv[:, 1], s200, linewidth2, facecolorsnone, edgecolorsblack, labelsupport vectors) plt.xlabel(petal length (cm)) plt.ylabel(petal width (cm)) plt.title(Support vectors of RBF SVM on Iris) plt.legend() plt.show() print(支持向量数量:, len(sv)) print(支持向量所在样本索引:, clf.support_)运行输出中空心圆圈代表支持向量它们通常紧贴在决策边界两侧。解释这句话时要注意在软间隔 SVM 中支持向量不只是边界上的点还包括被误分类的样本所以数量可能比想象中多。clf.support_给出的是支持向量在X_train2中的索引可以用来回溯原始样本是哪一朵花。实验报告里放一张这样的图再配上「支持向量数量为 47说明边界区域存在重叠需要软间隔容错」的说明比只贴准确率要有信息量得多。5. 把实验报告写成一页可复现的结论5.1 实验报告的标准结构从环境到结论的五个小节拿到 SVM 作业的实验报告要求时先不要急着写原理而是按照「实验目标 - 数据说明 - 模型与参数 - 结果分析 - 结论反思」这个顺序搭框架。这个结构与实际机器学习项目交付文档完全一致导师通常也希望看到这样的组织方式。实验目标里写清楚要解决什么问题用 Iris 数据训练 SVM比较不同核函数和参数的效果并对支持向量概念形成直观理解。数据说明里写样本量、特征数、类别分布和 train/test 划分规则。模型与参数部分列出线性核、RBF 核、C 和 gamma 的取值范围。结果分析放表格、可视化图和关键指标。最后写结论反思指出实验中哪些结果符合预期、哪些地方有意外。5.2 记录实验环境与随机种子保证结果可复现实验报告如果不写环境版本三个月后自己都复现不出来。常见做法是把 Python 及相关库的版本放在报告附录里至少包含以下内容依赖项版本建议用途Python3.10解释器scikit-learn1.2SVM 实现numpy1.24数组计算pandas2.0数据操作matplotlib3.7可视化版本号可以用pip list或python -c import sklearn; print(sklearn.__version__)查询不用逐一手动记录。更重要的一点是像第 2 章那样固定random_state否则每次运行结果不同实验报告中的数字会前后矛盾。如果你在报告里写了一个准确率请确保这个准确率对应的代码确实能复现出相同结果。5.3 用三个指标综合判断 SVM 是否「真的学会」作业里最容易出现的错误是只看测试准确率。准确率在 Iris 上普遍高于 0.9单看这个数字很难区分模型好坏。我建议在结论部分至少给出三个维度的判断交叉验证得分、支持向量数量和错分样本分布。交叉验证得分反映模型在不同数据划分下是否稳定支持向量数量反映分类边界的复杂程度数量过少可能过于平滑数量过多可能过拟合错分样本分布能看出哪两个类别最容易混淆。做一个简单的验证把训练好的模型在完整 150 条数据上重新预测统计每个错误预测样本的特征值你会发现错误大多集中在靠近 versicolor/virginica 边界的几个样本上。这个现象可以在实验报告里写成「SVM 在低维特征空间中依然存在少量不可分样本这是数据本身的标签重叠造成的增大 C 并不能完全消除。」这样一句话比任何抽象的「模型效果良好」都有说服力。最后可以在报告末尾附上一条参数调整建议对 Iris 这类小数据集C1.0, gamma0.1的 RBF 核通常可以得到准确率与泛化能力的平衡点而线性核更适合作为可解释性要求的兜底方案。本文还有配套的精品资源点击获取