尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

机器学习SVM作业实战:基于Iris鸢尾花数据集的分类项目完整解析

机器学习SVM作业实战:基于Iris鸢尾花数据集的分类项目完整解析 简介这份资源面向机器学习初学者与高校学生围绕经典Iris鸢尾花数据集完成SVM分类实验适合作为课程作业参考或算法入门练手项目。压缩包共18个文件约631KB包含2个Python源码文件、2份docx实验报告、7张png结果图与若干xml配置及工程文件源码与报告相互对应便于对照理解建模流程。实验基于Python 3.9的IDLE环境借助sklearn完成数据加载、模型训练与评估用numpy处理数组运算并通过Matplotlib绘制分类结果与ROC曲线覆盖从数据准备到结果可视化的完整链路。目前已有970人学习下载读者可参考其中的代码组织方式、报告撰写结构与实验结论分析快速复现SVM分类过程并在此基础上调整核函数与参数加深对支持向量机原理的理解。1. 从一份 SVM 作业说起Iris 鸢尾花分类到底在练什么很多人第一次接触机器学习绕不开两个东西一个是吴恩达机器学习作业里反复出现的 SVM另一个是 Iris 鸢尾花数据集。这份「机器学习SVM作业基于Iris鸢尾花的数据样本实现SVM分类项目源码报告」听起来像学生作业但它其实是一套非常完整的分类项目最小闭环数据加载、特征分析、模型训练、参数调优、评估可视化、报告撰写。把这套流程吃透你换任何数据集做二分类或多分类骨架都不用重写。Iris 数据集只有 150 个样本、4 个特征、3 个类别小到能在笔记本上秒级跑完但它的价值在于「干净且可分」。用 SVM 在它上面做分类你能清楚看到核函数、惩罚系数 C、gamma 这些参数到底怎么影响决策边界。对新手来说这是理解 SVM 从硬间隔到软间隔、从线性到非线性的最佳沙盘对熟手来说这是验证自己评估流程和调参直觉的基准盘。下面我按实际做项目的顺序把这份作业从零复现一遍顺带把容易翻车的地方标出来。2. 数据加载与探索先把 Iris 的四个特征摸清楚2.1 用 sklearn 加载 Iris 并确认数据结构Iris 数据集在 sklearn 里自带不需要额外下载。但很多人直接load_iris()拿到数据就扔进模型连特征名和类别分布都没看后面画图和分析报告时就会卡壳。我一般先做三件事看形状、看特征名、看类别是否均衡。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 # 特征列是 sepal length/width、petal length/width单位 cm print(数据形状:, df.shape) print(特征名:, iris.feature_names) print(类别分布:\n, df[target].value_counts()) # 把 target 数字映射回类别名报告里写起来更直观 target_map {i: name for i, name in enumerate(iris.target_names)} df[species] df[target].map(target_map) print(df.head())这段代码的关键在as_frameTrue它把特征和标签合成一个 DataFrame列名就是sepal length (cm)这类可读名称。value_counts()确认三个类别各 50 个样本完全均衡所以后面不需要做重采样。参数上没什么可调的但要注意iris.target_names返回的是 numpy 数组映射时用enumerate转成字典更稳。2.2 特征分布与相关性为什么 petal 比 sepal 更管用Iris 四个特征里花瓣长度和花瓣宽度的区分度远高于花萼。这个结论不是背来的画个箱线图或算一下类间均值就能看出来。做报告时把这一步写进去比直接甩模型准确率有说服力得多。import matplotlib.pyplot as plt import seaborn as sns # 箱线图看每个特征在三个类别下的分布差异 fig, axes plt.subplots(2, 2, figsize(10, 8)) for idx, feature in enumerate(iris.feature_names): ax axes[idx // 2, idx % 2] sns.boxplot(xspecies, yfeature, datadf, axax) ax.set_title(feature) plt.tight_layout() plt.show() # 相关性热力图看特征之间是否冗余 plt.figure(figsize(6, 5)) sns.heatmap(df[iris.feature_names].corr(), annotTrue, cmapcoolwarm) plt.title(Feature Correlation) plt.show()箱线图里你会看到petal length和petal width在 setosa 和另外两类之间几乎完全分开而 versicolor 和 virginica 在花瓣特征上有少量重叠。相关性热力图通常显示花瓣长度和花瓣宽度高度相关0.96 左右这意味着两者信息冗余但 SVM 对冗余特征不敏感所以不必强行做特征选择。如果报告里要写特征工程可以提一句「基于箱线图观察花瓣特征区分度更高但保留全部四个特征对 SVM 影响不大」。提示画图时如果中文标题乱码加plt.rcParams[font.sans-serif] [SimHei]但报告里建议用英文标题避免环境差异。3. SVM 分类实现从线性核到 RBF 核的完整训练流程3.1 划分训练集与测试集stratify 不能省Iris 虽然均衡但随机划分仍可能让某一类在测试集里偏少。用stratifyy保证训练集和测试集类别比例一致这是分类任务的基本习惯。测试集比例我一般设 0.2 到 0.3150 个样本用 0.2 就是 30 个测试样本足够看出问题。from sklearn.model_selection import train_test_split X df[iris.feature_names].values y df[target].values # stratifyy 保证按类别比例分层抽样random_state 固定便于复现 X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42, stratifyy ) print(训练集:, X_train.shape, 测试集:, X_test.shape)random_state42是为了让每次运行结果一致报告里的数字才能对得上。stratifyy在类别不均衡时更重要Iris 上算是个好习惯的养成。注意X取.values变成 numpy 数组后面 SVM 接受这种格式如果保留 DataFramesklearn 也能跑但某些旧版本会警告特征名问题。3.2 线性核 SVM先拿一个基线出来不要一上来就 RBF 核调参先用线性核跑一个基线。Iris 在花瓣特征上近似线性可分线性核往往能到 95% 以上。有了基线后面调 RBF 才知道提升来自哪里。from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report # 线性核C 默认 1.0先不调 svm_linear SVC(kernellinear, C1.0, random_state42) svm_linear.fit(X_train, y_train) y_pred_linear svm_linear.predict(X_test) print(线性核准确率:, accuracy_score(y_test, y_pred_linear)) print(classification_report(y_test, y_pred_linear, target_namesiris.target_names))classification_report会输出每个类别的 precision、recall、f1-score。Iris 上通常 setosa 全对versicolor 和 virginica 之间偶尔错一两个。C1.0是默认惩罚系数控制间隔宽度和误分类惩罚的权衡C 越大越不容忍错分容易过拟合C 越小间隔越宽可能欠拟合。线性核下 C 的影响相对温和但报告里最好附一个 C 值对比表。3.3 RBF 核与参数网格gamma 和 C 怎么配RBF 核是 SVM 在中小规模数据上的默认选择它把样本映射到无限维空间能处理非线性边界。但 RBF 有两个关键参数C和gamma。gamma控制单个样本的影响范围越大越容易过拟合越小越平滑。我一般用GridSearchCV在训练集上交叉验证选参而不是拿测试集反复试。from sklearn.model_selection import GridSearchCV # 参数网格C 和 gamma 各取几个量级 param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1], kernel: [rbf] } # 5 折交叉验证scoring 用准确率 grid GridSearchCV(SVC(random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1) grid.fit(X_train, y_train) print(最佳参数:, grid.best_params_) print(交叉验证最佳得分:, grid.best_score_) # 用最佳模型在测试集上评估 best_svm grid.best_estimator_ y_pred_best best_svm.predict(X_test) print(测试集准确率:, accuracy_score(y_test, y_pred_best))GridSearchCV会对每组参数做 5 折交叉验证n_jobs-1用满 CPU 核。Iris 数据小16 组参数几秒就跑完。best_params_通常落在C1或C10、gamma0.1附近但不同random_state会有细微差异。注意不要用测试集去选参数否则报告里的准确率就是「偷看」来的严谨性会打折扣。注意如果gamma设得过大比如 10模型会把每个训练样本都当成一个簇训练集准确率 100% 但测试集可能掉到 70% 以下这是典型的过拟合信号。4. 评估与可视化让报告里的结论站得住脚4.1 混淆矩阵与决策边界两个必画的图准确率只是一个数字混淆矩阵能看出错在哪两类之间。决策边界图则直观展示 SVM 怎么切分特征空间。Iris 有四个特征画决策边界只能选两个通常选花瓣长度和花瓣宽度因为这两个区分度最高。from sklearn.metrics import confusion_matrix import seaborn as sns # 混淆矩阵 cm confusion_matrix(y_test, y_pred_best) plt.figure(figsize(6, 5)) sns.heatmap(cm, annotTrue, fmtd, cmapBlues, xticklabelsiris.target_names, yticklabelsiris.target_names) plt.xlabel(Predicted) plt.ylabel(Actual) plt.title(Confusion Matrix - RBF SVM) plt.show() # 决策边界只用花瓣两个特征重新训练一个 SVM 用于可视化 X_2d df[[petal length (cm), petal width (cm)]].values X_train_2d, X_test_2d, y_train_2d, y_test_2d train_test_split( X_2d, y, test_size0.2, random_state42, stratifyy ) svm_2d SVC(kernelrbf, Cgrid.best_params_[C], gammagrid.best_params_[gamma]) svm_2d.fit(X_train_2d, y_train_2d) # 生成网格点预测类别画填充等高线 x_min, x_max X_2d[:, 0].min() - 0.5, X_2d[:, 0].max() 0.5 y_min, y_max X_2d[:, 1].min() - 0.5, X_2d[:, 1].max() 0.5 xx, yy np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02)) Z svm_2d.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape) plt.figure(figsize(8, 6)) plt.contourf(xx, yy, Z, alpha0.3, cmapviridis) plt.scatter(X_2d[:, 0], X_2d[:, 1], cy, cmapviridis, edgecolorsk) plt.xlabel(Petal Length (cm)) plt.ylabel(Petal Width (cm)) plt.title(SVM Decision Boundary (RBF Kernel)) plt.show()混淆矩阵里如果 versicolor 和 virginica 之间有 1 到 2 个错分属于正常范围。决策边界图会显示 setosa 被完全隔离在左下角另外两类之间有一条弯曲的边界。这张图放进报告比单纯写「准确率 96%」更有信息量。注意可视化用的 2D 模型和之前 4D 模型不是同一个参数虽然一样但特征少了两个边界形状会略有不同报告里要说明这一点。4.2 交叉验证曲线C 和 gamma 各自怎么影响准确率网格搜索给了最佳组合但报告里最好展示单参数变化趋势。固定一个参数扫另一个画折线图能看出模型对哪个参数更敏感。# 固定 gamma0.1扫 C C_values [0.01, 0.1, 1, 10, 100, 1000] train_scores, test_scores [], [] for C in C_values: svm SVC(kernelrbf, CC, gamma0.1, random_state42) svm.fit(X_train, y_train) train_scores.append(svm.score(X_train, y_train)) test_scores.append(svm.score(X_test, y_test)) plt.figure(figsize(8, 5)) plt.plot(C_values, train_scores, markero, labelTrain) plt.plot(C_values, test_scores, markers, labelTest) plt.xscale(log) plt.xlabel(C (log scale)) plt.ylabel(Accuracy) plt.legend() plt.title(Effect of C on SVM Accuracy (gamma0.1)) plt.show()通常你会看到 C 从 0.01 增到 1 时测试准确率上升超过 10 后训练准确率接近 100% 但测试不再提升甚至下降。这就是过拟合的直观证据。gamma的扫描同理gamma太大时测试准确率会明显下滑。报告里把这两张图放进去调参部分就有了数据支撑而不是一句「我用网格搜索找到了最佳参数」。5. 避坑与排查Iris 跑 SVM 最容易翻车的 5 个地方5.1 现象准确率 100%但换个 random_state 就掉到 90%原因Iris 只有 150 个样本测试集 30 个错一个就差 3.3 个百分点。如果只跑一次就写报告数字波动很大。解决用cross_val_score做 10 折交叉验证报告里写平均准确率和标准差而不是单次测试集准确率。from sklearn.model_selection import cross_val_score scores cross_val_score(best_svm, X, y, cv10, scoringaccuracy) print(10折交叉验证: %.4f ± %.4f % (scores.mean(), scores.std()))5.2 现象StandardScaler 之后准确率反而降了原因Iris 四个特征量纲接近都是厘米SVM 对尺度敏感但这里差异不大。如果强行标准化可能改变核函数对距离的感知导致边界偏移。解决先不标准化跑基线如果准确率明显低于预期再试标准化。Iris 上通常不需要但报告里可以提一句「特征量纲一致未做标准化」。5.3 现象gamma 设成 scale 和设成具体数字结果差很多原因sklearn 的gammascale默认是1 / (n_features * X.var())Iris 方差小算出来 gamma 偏大可能过拟合。解决显式指定 gamma 网格搜索不要依赖默认值。报告里写清楚 gamma 的搜索范围。5.4 现象多分类时 SVM 内部怎么决策的搞不清原因SVM 原生是二分类sklearn 用 one-vs-one 策略3 个类别训练 3 个分类器。解决知道这个机制后看混淆矩阵时就能理解为什么 versicolor 和 virginica 容易混——它们在一对一投票里可能互相「抢票」。报告里可以加一句「采用 one-vs-one 多分类策略」。5.5 现象决策边界图上的点颜色和类别对不上原因plt.scatter的cy传入的是数字标签cmap映射后颜色顺序可能和target_names不一致。解决用cy配合cmapviridis时在图例里手动标注 0setosa、1versicolor、2virginica或者用ListedColormap指定颜色。提示以上五条里第 1 条和第 3 条最常出现在作业报告里因为单次划分和默认 gamma 太容易让人误以为模型已经调好了。6. 把作业变成可复用的分类模板三个进阶习惯做完 Iris 这份 SVM 作业如果只交一份报告就结束有点浪费。我后来带新人时会让他们把代码整理成三个可复用件一个数据加载函数、一个训练评估函数、一个参数扫描函数。这样换到 wine 数据集或乳腺癌数据集改几行就能跑。第一个习惯是固定随机种子并记录。random_state42不是玄学是为了让报告里的每个数字都能被复现。我一般会在脚本开头写SEED 42所有涉及随机的地方都引用它。第二个习惯是评估指标不只看准确率。Iris 均衡准确率够用但如果换成不均衡数据就要看 f1-score 和 recall。classification_report每次必打花不了几秒。第三个习惯是保存最佳模型和参数。用joblib.dump(best_svm, svm_iris.pkl)存下来下次直接加载不用重新训练。import joblib # 保存模型和最佳参数 joblib.dump(best_svm, svm_iris_rbf.pkl) with open(best_params.txt, w) as f: f.write(str(grid.best_params_)) # 加载验证 loaded_svm joblib.load(svm_iris_rbf.pkl) print(加载模型测试准确率:, loaded_svm.score(X_test, y_test))这段代码里joblib比pickle更适合存 sklearn 模型因为内部用了 numpy 数组优化。保存参数到文本文件是为了写报告时直接引用不用翻控制台记录。最后一个技巧是关于报告写作的把「准确率 96%」改成「在 10 折交叉验证下平均准确率 96.7%标准差 0.021其中 versicolor 和 virginica 之间存在少量错分」。前者是数字后者是结论。我吃过亏早期报告只写准确率被问「这个 96% 是怎么来的、稳不稳定」时答不上来。后来养成习惯每个指标都带上下文和波动范围报告的可信度完全不一样。希望帮到你。本文还有配套的精品资源点击获取
返回列表