ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

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

机器学习SVM作业实战:基于Iris鸢尾花数据集的分类项目全流程解析 简介这份资源面向机器学习初学者与需要完成课程作业的高校学生围绕经典Iris鸢尾花数据集实现支持向量机分类任务帮助读者在动手实践中理解SVM原理与调参流程。压缩包共18个文件约631KB包含2个Python源码文件、2份docx实验报告、7张png结果图以及xml、iml等工程配置文件源码与报告相互对应便于对照阅读与复现。目前已有970人学习下载具备一定的参考热度。读者可从中获得完整的SVM分类实现代码、实验报告模板、分类结果可视化图表以及基于sklearn、numpy、matplotlib的模块使用示例既能直接运行验证也可作为课程作业的写作与排错参考适合作为机器学习入门阶段的实战素材。1. 从一份 Iris 作业说起SVM 分类到底在做什么很多人第一次接触机器学习都是从一份 Iris 鸢尾花数据集的 SVM 分类作业开始的。标题里写着“机器学习SVM作业基于Iris鸢尾花的数据样本实现SVM分类项目源码报告”看起来像是一份普通的课程作业但它其实覆盖了一条完整的工程链路数据加载、特征选择、模型训练、超参数调优、评估可视化最后还要写出一份能自圆其说的报告。Iris 数据集只有 150 个样本、4 个特征、3 个类别规模小到可以在一张 A4 纸上画完但正因为小它才适合用来把 SVM 的每一个参数、每一步决策都掰开揉碎讲清楚。如果你正在做机器学习入门、期末复习或者想找一个能跑通的最小分类项目这份作业的骨架值得认真拆一遍。它不只是一个“调包”练习而是理解分类评估、核函数选择、软间隔与硬间隔差异的入口。下面我会按实际动手的顺序把从零复现这个项目的路径、参数设置和常见翻车点讲透。2. 数据准备与特征工程Iris 数据集怎么切、怎么标准化2.1 加载 Iris 数据并确认三个类别的分布Iris 数据集在 scikit-learn 里可以直接加载不需要额外下载。但直接load_iris()拿到的是字典结构需要转成 DataFrame 才方便做后续分析和可视化。先看数据的基本形态from sklearn.datasets import load_iris import pandas as pd iris load_iris() df pd.DataFrame(iris.data, columnsiris.feature_names) df[target] iris.target print(df.head()) print(df[target].value_counts()) print(df.describe())这段代码做了三件事把特征矩阵转成带列名的 DataFrame把标签列加进去然后打印前五行、类别分布和描述性统计。value_counts()会告诉你三个类别各 50 个样本完全均衡不需要做重采样。describe()则能看出四个特征的量纲差异——花瓣长度单位是厘米数值在 1 到 7 之间而萼片宽度也在类似范围整体量纲接近但标准化仍然是必要步骤原因在下一节说明。参数上唯一需要注意的是load_iris()返回的target是 0、1、2 三个整数不是字符串。如果你后面要做可视化可以手动映射成setosa、versicolor、virginica但训练时用整数标签即可。2.2 为什么 SVM 必须做标准化一个容易被忽略的细节SVM 的核心是寻找一个超平面让不同类别之间的间隔最大化。这个“间隔”是建立在特征空间距离上的如果某个特征的数值范围远大于其他特征它就会主导距离计算导致模型忽略掉数值范围小但同样重要的特征。Iris 的四个特征量纲虽然接近但花瓣长度和萼片宽度的方差不同标准化之后能让每个特征对距离的贡献更均衡。常见做法是使用StandardScaler做 Z-score 标准化from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split X df.drop(target, axis1) y df[target] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test)这里有几个参数需要留意。test_size0.3表示测试集占 30%Iris 总共 150 条训练集 105 条、测试集 45 条足够做一次可靠的评估。stratifyy保证训练集和测试集里三个类别的比例都是 1:1:1避免随机切分导致某个类别在测试集里缺失。random_state42是为了结果可复现换一个种子会得到不同的切分但评估指标波动不会太大。标准化时有一个血泪经验fit_transform只能用在训练集上测试集必须用同一个 scaler 做transform。如果对测试集重新fit就会引入数据泄露评估结果会虚高实际部署时直接翻车。2.3 特征可视化用散点图确认类别是否线性可分在训练之前先画一张散点图能帮你判断该选线性核还是 RBF 核。Iris 的四个特征里花瓣长度和花瓣宽度的区分度最高用这两个特征画二维散点图import matplotlib.pyplot as plt plt.figure(figsize(8, 6)) for target, color, label in zip([0, 1, 2], [r, g, b], iris.target_names): plt.scatter( df[df[target] target][petal length (cm)], df[df[target] target][petal width (cm)], ccolor, labellabel, alpha0.7 ) plt.xlabel(Petal Length (cm)) plt.ylabel(Petal Width (cm)) plt.legend() plt.title(Iris: Petal Length vs Petal Width) plt.show()从图上能明显看到setosa 类别和另外两类完全分开一条直线就能切开但 versicolor 和 virginica 在边界区域有重叠线性核可能只能做到 95% 左右的准确率而 RBF 核能把准确率推到 97% 以上。这个观察直接决定了下一章核函数的选择方向。如果跳过这一步直接上默认参数你可能会在调参时多走很多弯路。3. SVM 模型训练核函数、C 值和 gamma 怎么定3.1 线性核与 RBF 核的选型依据scikit-learn 的SVC默认使用 RBF 核但 Iris 这个数据集上线性核和 RBF 核的差距并不大。线性核的优势是模型简单、可解释性强能直接拿到权重系数RBF 核的优势是能拟合非线性边界在 versicolor 和 virginica 的重叠区域表现更好。我一般会先跑一个线性核作为基线from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report svm_linear SVC(kernellinear, C1.0, random_state42) svm_linear.fit(X_train_scaled, y_train) y_pred_linear svm_linear.predict(X_test_scaled) print(Linear Kernel Accuracy:, accuracy_score(y_test, y_pred_linear)) print(classification_report(y_test, y_pred_linear, target_namesiris.target_names))C1.0是默认的惩罚系数表示对误分类的容忍度。C 越大模型越倾向于把所有训练样本分对间隔越窄容易过拟合C 越小间隔越宽允许一些样本落在间隔内甚至分错泛化能力可能更好。线性核在 Iris 上通常能拿到 95% 到 97% 的准确率具体取决于随机切分。然后换 RBF 核对比svm_rbf SVC(kernelrbf, C1.0, gammascale, random_state42) svm_rbf.fit(X_train_scaled, y_train) y_pred_rbf svm_rbf.predict(X_test_scaled) print(RBF Kernel Accuracy:, accuracy_score(y_test, y_pred_rbf)) print(classification_report(y_test, y_pred_rbf, target_namesiris.target_names))gammascale是 scikit-learn 的默认值等于1 / (n_features * X.var())。gamma 越大单个样本的影响范围越小决策边界越曲折容易过拟合gamma 越小影响范围越大边界越平滑。在 Iris 上gamma 从 0.01 到 1 之间调准确率变化不会超过 2 个百分点但如果你把 gamma 设到 10 以上测试集准确率会明显下降。3.2 用 GridSearchCV 做超参数搜索的完整流程手动试参数效率太低实际项目中我会直接用网格搜索把 C 和 gamma 的组合跑一遍。下面这段代码可以直接抄from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1, scale], kernel: [rbf] } grid GridSearchCV( SVC(random_state42), param_grid, cv5, scoringaccuracy, n_jobs-1, verbose1 ) grid.fit(X_train_scaled, y_train) print(Best Parameters:, grid.best_params_) print(Best Cross-Validation Score:, grid.best_score_) best_svm grid.best_estimator_ y_pred_best best_svm.predict(X_test_scaled) print(Test Accuracy:, accuracy_score(y_test, y_pred_best))cv5表示 5 折交叉验证训练集 105 条被分成 5 份每次用 4 份训练、1 份验证轮流 5 次最后取平均。scoringaccuracy是评估指标也可以换成f1_macro尤其在类别不均衡时更合适。n_jobs-1表示用满所有 CPU 核心并行搜索Iris 数据量小几秒钟就能跑完。搜索空间里 C 取了 0.1、1、10、100 四个量级gamma 取了 0.001 到 1 加上scale。实际跑下来最优组合通常是C1或C10gammascale或gamma0.1测试集准确率在 97% 左右。如果最优 C 落在搜索边界上比如选到了 100说明应该把搜索范围往更大的方向扩反之亦然。3.3 训练完成后的模型保存与加载作业报告里通常要求附上源码但实际项目中你还需要把训练好的模型保存下来避免每次预测都重新训练。scikit-learn 推荐用joblibimport joblib joblib.dump(best_svm, svm_iris_model.pkl) joblib.dump(scaler, scaler_iris.pkl) loaded_model joblib.load(svm_iris_model.pkl) loaded_scaler joblib.load(scaler_iris.pkl) new_sample [[5.1, 3.5, 1.4, 0.2]] new_sample_scaled loaded_scaler.transform(new_sample) print(loaded_model.predict(new_sample_scaled))注意scaler必须和模型一起保存因为预测时新数据要用同一个 scaler 做变换。如果只保存模型不保存 scaler加载后直接预测原始数据结果会完全错误。这个坑我在第一次部署时踩过排查了半天才发现是标准化没对齐。4. 评估与可视化准确率之外还要看什么4.1 混淆矩阵和分类报告的正确读法准确率只能告诉你“分对了多少”但分错的是哪一类、错得有多离谱需要看混淆矩阵。下面这段代码同时输出混淆矩阵和分类报告from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay import matplotlib.pyplot as plt cm confusion_matrix(y_test, y_pred_best) disp ConfusionMatrixDisplay(confusion_matrixcm, display_labelsiris.target_names) disp.plot(cmapBlues) plt.title(Confusion Matrix - SVM RBF Kernel) plt.show() print(classification_report(y_test, y_pred_best, target_namesiris.target_names))混淆矩阵的对角线是分对的样本数非对角线是分错的。在 Iris 上setosa 通常全部正确versicolor 和 virginica 之间会有 1 到 2 个互相错分。分类报告里的 precision 表示“预测为某一类的样本里有多少是真的”recall 表示“某一类的真实样本里有多少被找出来了”f1-score 是两者的调和平均。如果某个类别的 recall 明显偏低说明模型漏掉了这一类可能需要调整类别权重或增加该类样本。4.2 决策边界可视化把 RBF 核的“非线性”画出来RBF 核的决策边界不是直线但具体长什么样画出来最直观。用花瓣长度和花瓣宽度两个特征训练一个二维 SVM然后在网格上预测并填充颜色import numpy as np X_2d df[[petal length (cm), petal width (cm)]].values y_2d df[target].values scaler_2d StandardScaler() X_2d_scaled scaler_2d.fit_transform(X_2d) svm_2d SVC(kernelrbf, C1.0, gammascale, random_state42) svm_2d.fit(X_2d_scaled, y_2d) x_min, x_max X_2d_scaled[:, 0].min() - 0.5, X_2d_scaled[:, 0].max() 0.5 y_min, y_max X_2d_scaled[:, 1].min() - 0.5, X_2d_scaled[:, 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()]) Z Z.reshape(xx.shape) plt.figure(figsize(8, 6)) plt.contourf(xx, yy, Z, alpha0.3, cmapRdYlBu) plt.scatter(X_2d_scaled[:, 0], X_2d_scaled[:, 1], cy_2d, cmapRdYlBu, edgecolorsk) plt.xlabel(Petal Length (scaled)) plt.ylabel(Petal Width (scaled)) plt.title(SVM RBF Decision Boundary (2D)) plt.show()np.meshgrid生成网格点np.c_把两个特征拼成预测矩阵contourf填充决策区域。从图上能看到 setosa 区域是一条平滑的边界而 versicolor 和 virginica 之间的边界有弯曲这正是 RBF 核把数据映射到高维空间后的效果。如果换成线性核边界会是一条直线重叠区域会有更多错分。4.3 交叉验证曲线判断模型是否过拟合或欠拟合单次切分的评估结果有随机性用交叉验证曲线能看到模型在不同训练集大小下的表现from sklearn.model_selection import learning_curve train_sizes, train_scores, test_scores learning_curve( SVC(kernelrbf, C1.0, gammascale, random_state42), X_train_scaled, y_train, train_sizesnp.linspace(0.1, 1.0, 10), cv5, scoringaccuracy, n_jobs-1 ) train_mean np.mean(train_scores, axis1) test_mean np.mean(test_scores, axis1) plt.figure(figsize(8, 6)) plt.plot(train_sizes, train_mean, o-, labelTraining Accuracy) plt.plot(train_sizes, test_mean, o-, labelCross-Validation Accuracy) plt.xlabel(Training Set Size) plt.ylabel(Accuracy) plt.legend() plt.title(Learning Curve - SVM RBF) plt.show()如果训练准确率远高于交叉验证准确率说明过拟合需要增大 C 或减小 gamma如果两条曲线都很低且靠得很近说明欠拟合需要增大 gamma 或换更复杂的核。Iris 上通常两条曲线在训练集达到 60 条以后就收敛到 95% 以上差距很小说明模型泛化能力不错。5. 避坑与排查Iris SVM 作业里最容易翻车的五个点5.1 标准化顺序错误导致评估虚高现象测试集准确率 99%但换一组新数据预测结果完全不对。原因对训练集和测试集分别做了fit_transform测试集的均值和方差与训练集不一致模型学到的边界和实际预测时的数据分布不匹配。解决永远只在训练集上fit测试集和新数据都用同一个 scaler 做transform。如果已经写错了把fit_transform改成transform重新跑一遍。5.2 随机切分导致某个类别在测试集里缺失现象classification_report里某个类别的 support 为 0报 warning。原因train_test_split没有加stratifyy随机切分时某个类别可能全部落在训练集。解决加上stratifyy保证训练集和测试集的类别比例一致。Iris 三个类别各 50 条不加 stratify 时虽然概率低但一旦发生评估结果就不可信。5.3 gamma 设得过大导致过拟合现象训练集准确率 100%测试集准确率只有 80% 多。原因gamma设得太大比如手动设成 10 或 100每个样本的影响范围缩小到只覆盖自己模型把训练数据里的噪声也学进去了。解决用gammascale作为起点然后在[0.001, 0.01, 0.1, 1]范围内搜索。如果最优 gamma 落在边界上再往外扩。5.4 忘记保存 scaler 导致部署失败现象模型文件加载成功但预测结果全是同一个类别。原因只保存了SVC模型没有保存StandardScaler预测时用原始数据直接输入模型而模型是在标准化后的数据上训练的。解决用joblib.dump同时保存模型和 scaler预测时先transform再predict。这个坑在作业里不常见但一旦进入实际项目几乎每个人都会踩一次。5.5 用准确率评估类别不均衡数据现象某个类别有 90 条另外两个类别各 30 条准确率 90% 但 minority 类别的 recall 只有 50%。原因准确率在类别不均衡时会被多数类主导。解决改用f1_macro或balanced_accuracy作为评估指标或者在SVC里设置class_weightbalanced。Iris 本身是均衡的但如果你用这个代码框架去跑其他数据集这一点必须注意。6. 从作业到项目把 Iris SVM 扩展成可复用的分类模板Iris 作业跑通之后最有价值的动作不是交报告而是把这套流程抽象成一个可复用的分类模板。我自己的习惯是写一个train_svm_classifier函数输入特征矩阵和标签输出最优模型、评估报告和可视化图表。这样下次遇到新的分类任务只需要换数据不用重写训练逻辑。def train_svm_classifier(X, y, test_size0.3, random_state42): X_train, X_test, y_train, y_test train_test_split( X, y, test_sizetest_size, random_staterandom_state, stratifyy ) scaler StandardScaler() X_train_scaled scaler.fit_transform(X_train) X_test_scaled scaler.transform(X_test) param_grid { C: [0.1, 1, 10, 100], gamma: [0.001, 0.01, 0.1, 1, scale], kernel: [rbf] } grid GridSearchCV( SVC(random_staterandom_state), param_grid, cv5, scoringf1_macro, n_jobs-1 ) grid.fit(X_train_scaled, y_train) best_model grid.best_estimator_ y_pred best_model.predict(X_test_scaled) print(Best Params:, grid.best_params_) print(classification_report(y_test, y_pred)) return best_model, scaler, grid.best_score_这个函数里我把scoring从accuracy换成了f1_macro因为实际项目里类别不均衡是常态f1_macro 对少数类更友好。返回三个值最优模型、scaler、交叉验证得分。拿到新数据后先检查特征数量和量纲如果特征数量不同需要重新调整网格搜索的范围如果量纲差异大标准化这一步不能省。验证这个模板是否可靠我一般会做两件事。第一用不同的random_state跑 5 次看测试集 f1_macro 的波动范围如果波动超过 5 个百分点说明数据量太小或切分方式有问题。第二拿一个从未参与训练的新样本手动预测确认输出类别和概率合理。SVC默认不输出概率如果需要概率值要在初始化时加probabilityTrue但这会显著增加训练时间Iris 上大概多花 2 到 3 秒数据量大时慎用。最后说一个我自己的教训早期做作业时我把所有精力花在调参上C 从 0.1 试到 1000gamma 试了十几个值准确率从 96% 提到 97%但报告里写不出为什么选这个参数。后来才明白Iris 这种小数据集参数搜索的边际收益很低把数据切分、标准化、评估指标这三件事做对比多调 1% 准确率重要得多。如果你正在做这份作业先把流程跑通再回头理解每个参数的含义报告自然有话可写。希望帮到你。本文还有配套的精品资源点击获取
返回列表