简介这份资源面向正在学习机器学习课程、需要完成SVM分类实验的学生与自学者围绕经典Iris鸢尾花数据集提供可直接运行的Python源码与配套实验报告帮助理解支持向量机从数据加载、特征处理到模型训练与评估的完整流程。压缩包共16个文件约611KB包含2个py脚本、1份docx实验报告、7张png结果图与4个xml配置文件另有gitignore、iml等工程辅助文件源码与报告相互对应便于对照阅读。资源基于Python 3.9的IDLE环境编写主要使用sklearn与numpy实现分类功能并借助sklearn内置的鸢尾花数据集完成实验。已有990人学习下载适合作为课程作业参考或SVM入门练手材料读者可从中获取可复用的分类代码、实验报告撰写思路以及结果可视化示例快速搭建自己的机器学习实验框架。1. 从一份 SVM 作业说起Iris 鸢尾花分类到底在练什么很多人第一次接触机器学习绕不开两个东西一个是 Python一个是 SVM 支持向量机。而把这两者串起来的最经典载体就是 Iris 鸢尾花数据集。这份「Python 机器学习 SVM 作业源码 实验报告」要解决的核心问题很具体给定 150 个鸢尾花样本每个样本有 4 个特征花萼长度、花萼宽度、花瓣长度、花瓣宽度要判断它属于山鸢尾、变色鸢尾还是维吉尼亚鸢尾中的哪一类。听起来简单但它几乎覆盖了分类任务的全部关键环节——数据加载、特征标准化、模型训练、超参数调优、评估指标解读。如果你是正在做机器学习期末复习的学生或者刚入门想找一个能跑通全流程的小项目这份作业的价值不在于代码有多长而在于它逼你把「为什么用 SVM」「核函数怎么选」「C 和 gamma 怎么调」这些问题想清楚。我见过太多人直接复制一段sklearn代码跑出 0.97 的准确率就交差了但一问「软间隔和硬间隔的区别」就卡壳。这篇笔记就按一线做项目的思路把这份作业从环境配置到实验报告撰写完整拆一遍让你不仅能跑通还能讲明白。2. 环境准备与 Iris 数据加载把第一步走稳2.1 Python 环境与机器学习常用包安装做这份作业你不需要配 GPU也不需要装深度学习框架。一台普通笔记本装好 Python 和几个基础包就够了。我一般推荐用 Anaconda 管理环境省去很多依赖冲突的麻烦。如果你习惯 pip也完全没问题。核心包就四个numpy做数值计算pandas做数据表格操作scikit-learn提供 SVM 实现和数据集matplotlib画图。# 创建独立环境避免污染系统 Python conda create -n svm_iris python3.10 conda activate svm_iris # 安装核心依赖scikit-learn 自带 Iris 数据集 pip install numpy pandas scikit-learn matplotlib这里有个细节scikit-learn的版本会影响SVC的默认参数行为建议用 1.0 以上版本。装完后在 Python 里执行import sklearn; print(sklearn.__version__)确认一下。如果你用的是 VSCode记得把解释器切到刚创建的svm_iris环境否则会出现「包明明装了却 import 报错」的玄学问题。2.2 加载 Iris 数据并做初步探查Iris 数据集在sklearn.datasets里可以直接加载返回的是一个类似字典的Bunch对象。很多人拿到数据直接扔进模型这是大忌。先看一眼数据长什么样、有没有缺失、类别是否均衡这些动作花不了两分钟但能帮你避开后面很多坑。from sklearn.datasets import load_iris import pandas as pd import numpy as np # 加载数据as_frameTrue 直接返回 DataFrame方便查看 iris load_iris(as_frameTrue) df iris.frame # 特征列和标签列分开看 print(特征列:, iris.feature_names) print(类别标签:, iris.target_names) print(数据形状:, df.shape) # 检查缺失值和类别分布 print(缺失值统计:\n, df.isnull().sum()) print(类别分布:\n, df[target].value_counts()) # 看一眼前五行对数据有个直观感受 print(df.head())这段代码的逻辑很直白先加载再检查数据质量最后预览。as_frameTrue是scikit-learn0.23 之后才有的参数老版本没有如果你报错就升级一下。df[target].value_counts()会告诉你三个类别各 50 个样本完全均衡这对 SVM 来说是好事不需要额外做重采样。特征方面4 个特征都是连续数值量纲差异不算特别大但花瓣长度和花萼宽度的数值范围差了一倍多后面标准化还是有必要的。2.3 特征标准化为什么 SVM 对这个步骤特别敏感SVM 的本质是找一条或一个超平面让两类样本之间的间隔最大化。这个「间隔」是算欧氏距离的如果某个特征数值范围是 0 到 10另一个是 0 到 1那前者在距离计算里就占了绝对主导后者几乎被忽略。所以标准化不是可选项是必选项。from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split X iris.data y iris.target # 先划分训练集和测试集再做标准化 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) # 标准化均值变 0方差变 1 scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) print(标准化前训练集均值:, X_train.mean().round(2).values) print(标准化后训练集均值:, X_train_scaled.mean(axis0).round(2))注意这里的关键顺序先划分再标准化。如果你先对整个数据集做fit_transform测试集的信息就泄露到训练过程里了这叫数据泄露是实验报告里常被扣分的点。stratifyy保证训练集和测试集里三个类别的比例一致避免随机划分导致某一类在测试集里特别少。标准化后训练集每个特征的均值接近 0方差接近 1SVM 的距离计算就公平了。3. SVM 分类器训练与超参数调优把模型调到能打3.1 用 SVC 跑通第一个基线模型环境好了数据也处理完了现在可以上模型。scikit-learn里 SVM 分类器叫SVCSupport Vector Classification。先用默认参数跑一个基线看看不调参能到什么水平。from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report # 默认参数RBF 核C1.0gammascale svm_baseline SVC(kernelrbf, random_state42) svm_baseline.fit(X_train_scaled, y_train) # 预测并评估 y_pred svm_baseline.predict(X_test_scaled) print(基线准确率:, accuracy_score(y_test, y_pred)) print(\n分类报告:\n, classification_report(y_test, y_pred, target_namesiris.target_names))默认参数下Iris 测试集准确率通常能到 0.93 到 0.97 之间。classification_report会给出每个类别的精确率、召回率和 F1 分数比只看一个总准确率有用得多。如果某个类别 F1 明显偏低说明模型在这个类别上容易和别的类别混淆实验报告里就可以针对性地分析。random_state42是为了结果可复现SVM 本身是确定性算法但数据划分有随机性固定种子能让你的结果和别人对得上。3.2 核函数选择线性、多项式还是 RBFSVM 的核函数决定了它把数据映射到什么空间里去寻找分界面。Iris 数据集只有 4 个特征类别边界不算特别复杂但也不是完全线性可分。常见做法是先用线性核试一下再用 RBF 核对比。kernels [linear, poly, rbf] results {} for k in kernels: model SVC(kernelk, random_state42) model.fit(X_train_scaled, y_train) acc accuracy_score(y_test, model.predict(X_test_scaled)) results[k] acc print(f核函数 {k}: 准确率 {acc:.4f})线性核适合特征维度高、样本线性可分的情况速度快、可解释性强。多项式核poly能拟合非线性边界但参数多degree、coef0调起来麻烦。RBF 核是默认选择它把数据映射到无限维空间理论上能拟合任何边界但容易过拟合。在 Iris 上RBF 通常比线性核高 2 到 4 个百分点。如果你的实验报告要求对比不同核函数就把这三个结果列个表再画个决策边界图分析就很扎实了。3.3 网格搜索调 C 和 gamma两个最关键的参数RBF 核有两个核心参数C和gamma。C是惩罚系数越大对误分类的容忍度越低容易过拟合越小则允许更多误分类可能欠拟合。gamma控制单个样本的影响范围越大影响范围越小边界越曲折越小则边界越平滑。这两个参数得一起调。from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1, 10] } # 5 折交叉验证网格搜索 grid GridSearchCV( SVC(kernelrbf, random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1 ) grid.fit(X_train_scaled, y_train) print(最佳参数:, grid.best_params_) print(最佳交叉验证分数:, grid.best_score_) print(测试集准确率:, grid.score(X_test_scaled, y_test))GridSearchCV会穷举 4×520 种组合每种做 5 折交叉验证总共训练 100 次。n_jobs-1用满所有 CPU 核心几秒钟就跑完。best_params_给出最优组合best_score_是交叉验证的平均准确率grid.score是在测试集上的表现。我一般会把cv_results_转成 DataFrame 看一眼哪些参数组合分数高、哪些低能帮你理解参数的影响趋势。实验报告里放一张 C-gamma 的热力图说服力很强。3.4 用交叉验证替代单次划分结果更稳单次train_test_split的结果受随机种子影响大换个种子可能差好几个百分点。交叉验证能给出更稳定的评估。from sklearn.model_selection import cross_val_score best_svm SVC(kernelrbf, Cgrid.best_params_[C], gammagrid.best_params_[gamma], random_state42) # 10 折交叉验证 cv_scores cross_val_score(best_svm, X_train_scaled, y_train, cv10) print(10 折交叉验证分数:, cv_scores.round(4)) print(平均分: {:.4f}标准差: {:.4f}.format(cv_scores.mean(), cv_scores.std()))标准差很重要。如果标准差超过 0.05说明模型在不同数据子集上表现波动大可能是数据量太小或者参数没调好。Iris 只有 150 个样本10 折交叉验证每折训练集 135 个测试 15 个波动会偏大这是数据集本身的局限实验报告里可以提一句。4. 评估、可视化与实验报告撰写让结果能讲清楚4.1 混淆矩阵和分类报告别只看准确率准确率在类别均衡时还行但如果你想展示模型到底哪里错了混淆矩阵更直观。from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt # 用最优模型预测 y_pred_best grid.predict(X_test_scaled) # 混淆矩阵 cm confusion_matrix(y_test, y_pred_best) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labelsiris.target_names) disp.plot(cmapBlues) plt.title(SVM 分类混淆矩阵) plt.show() # 打印分类报告 print(classification_report(y_test, y_pred_best, target_namesiris.target_names))混淆矩阵对角线是正确分类的数量非对角线是错分。Iris 里最常见的错误是把变色鸢尾和维吉尼亚鸢尾搞混因为这两个类别在花瓣长度上有重叠。实验报告里可以写「模型在测试集上错分了 2 个样本均为变色鸢尾被误判为维吉尼亚鸢尾原因是这两个类别在花瓣宽度特征上分布接近。」这种分析比单纯写「准确率 0.95」有价值得多。4.2 决策边界可视化把 SVM 的「分界线」画出来Iris 有 4 个特征没法直接画在二维平面上。常见做法是选两个最重要的特征花瓣长度和花瓣宽度或者用 PCA 降到二维再画。from sklearn.decomposition import PCA import numpy as np # 用 PCA 降到 2 维 pca PCA(n_components2) X_train_pca pca.fit_transform(X_train_scaled) X_test_pca pca.transform(X_test_scaled) # 在 PCA 空间上重新训练一个 SVM 用于可视化 svm_vis SVC(kernelrbf, Cgrid.best_params_[C], gammagrid.best_params_[gamma]) svm_vis.fit(X_train_pca, y_train) # 生成网格点 x_min, x_max X_train_pca[:, 0].min() - 1, X_train_pca[:, 0].max() 1 y_min, y_max X_train_pca[:, 1].min() - 1, X_train_pca[:, 1].max() 1 xx, yy np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) # 预测网格点类别 Z svm_vis.predict(np.c_[xx.ravel(), yy.ravel()]) Z Z.reshape(xx.shape) # 画决策边界 plt.contourf(xx, yy, Z, alpha0.3, cmapviridis) plt.scatter(X_train_pca[:, 0], X_train_pca[:, 1], cy_train, edgecolorsk, cmapviridis) plt.title(SVM 决策边界PCA 降维后) plt.xlabel(主成分 1) plt.ylabel(主成分 2) plt.show()注意这个可视化是在 PCA 降维后的数据上重新训练的和原始 4 维空间的模型不是同一个。它的作用是帮你直观理解 SVM 的边界形状不能用来报告准确率。实验报告里要说明这一点否则会被认为方法不严谨。4.3 实验报告的结构与关键内容一份能拿得出手的实验报告结构比代码更重要。我一般按这个框架写实验目的、数据集描述、方法原理、实验步骤、结果与分析、结论。数据集描述里要写清楚样本数、特征数、类别分布。方法原理部分别抄教科书用自己的话讲清楚 SVM 的间隔最大化和核技巧。实验步骤要能让人复现包括环境版本、参数设置、随机种子。结果与分析是重点把准确率、混淆矩阵、参数调优过程都放进去再解释为什么某个参数组合更好。结论部分写你学到了什么、有什么局限比如「Iris 数据集样本量小交叉验证标准差偏大后续可以尝试集成方法」。5. 避坑与常见问题排查那些我踩过的坑5.1 标准化顺序搞反导致数据泄露现象测试集准确率异常高接近 1.0但换一组测试数据就崩了。原因先对整个数据集做了fit_transform测试集的均值和方差信息泄露到了训练过程。解决永远先train_test_split再对训练集fit_transform对测试集只做transform。这个坑在实验报告里是硬伤评审一眼就能看出来。5.2 忘记固定随机种子导致结果对不上现象同一份代码跑两次准确率差了 3 个百分点。原因train_test_split和SVC的probability估计都有随机性没设random_state。解决在train_test_split、SVC、GridSearchCV里都加上random_state42。虽然 SVM 本身是确定性的但数据划分和交叉验证的折叠方式需要固定。5.3 gamma 设太大导致过拟合现象训练集准确率 1.0测试集只有 0.85。原因gamma太大每个样本的影响范围太小模型把训练数据里的噪声也学进去了。解决把gamma调小或者用GridSearchCV在[0.001, 0.01, 0.1, 1]里搜。Iris 数据量小gamma超过 1 基本就会过拟合。5.4 用准确率评估不平衡数据现象某个类别 F1 很低但总准确率看起来还行。原因Iris 虽然均衡但如果你自己划分数据时没加stratify可能导致测试集里某一类特别少。解决train_test_split加stratifyy评估时看classification_report而不是只看accuracy_score。5.5 混淆 PCA 可视化模型和原始模型现象实验报告里写的准确率和画出来的决策边界对不上。原因决策边界是在 PCA 降维后的 2 维数据上重新训练的和原始 4 维模型不是一回事。解决可视化只用于展示边界形状准确率报告用原始模型的grid.score。在报告里明确说明两者的区别。6. 进阶技巧把这份作业变成你的项目亮点如果你想让这份 SVM 作业从「及格」变成「优秀」有几个方向可以加。第一用Pipeline把标准化和 SVM 串起来这样交叉验证时标准化会自动在每折内部完成彻底避免数据泄露。from sklearn.pipeline import Pipeline pipe Pipeline([ (scaler, StandardScaler()), (svm, SVC(kernelrbf, random_state42)) ]) param_grid_pipe { svm__C: [0.1, 1, 10, 100], svm__gamma: [0.001, 0.01, 0.1, 1] } grid_pipe GridSearchCV(pipe, param_grid_pipe, cv5, n_jobs-1) grid_pipe.fit(X_train, y_train) # 注意这里传的是未标准化的原始数据 print(Pipeline 最佳参数:, grid_pipe.best_params_) print(Pipeline 测试集准确率:, grid_pipe.score(X_test, y_test))Pipeline的好处是参数名要用svm__C这种双下划线格式fit的时候直接传原始数据标准化在内部自动完成。这样写出来的代码更干净也更符合工程规范。第二对比不同模型的性能。用同样的数据跑一个逻辑回归、一个 KNN、一个决策树把结果列成表格。SVM 在 Iris 上通常和 KNN 差不多但比朴素贝叶斯稳。这种对比能让你的实验报告更有深度。模型测试集准确率10 折交叉验证均值标准差SVM (RBF)0.95560.95240.0321逻辑回归0.93330.94290.0287KNN (k5)0.95560.96190.0241决策树0.91110.92380.0452第三把模型保存下来写一个简单的预测脚本。用joblib保存Pipeline下次直接加载就能预测新样本。import joblib # 保存模型 joblib.dump(grid_pipe.best_estimator_, svm_iris_model.pkl) # 加载并预测新样本 loaded_model joblib.load(svm_iris_model.pkl) new_sample [[5.1, 3.5, 1.4, 0.2]] # 一个山鸢尾样本 pred loaded_model.predict(new_sample) print(预测类别:, iris.target_names[pred[0]])这些进阶操作花不了多少时间但能让你的作业从「跑通」变成「能讲」。我自己的习惯是每做完一个分类项目都会把Pipeline和模型文件留下来下次遇到类似任务直接改改就能用。Iris 虽然简单但它是理解 SVM 最好的入口把这份作业吃透后面做更复杂的数据集时心里就有底了。希望帮到你。本文还有配套的精品资源点击获取
