
简介这份资源面向机器学习初学者与需要完成分类实验的工程人员聚焦支持向量机从二分类扩展到三分类的完整实现帮助读者理解一对一策略下多个二分类器的构建与投票预测逻辑。压缩包共6个文件以5个m脚本和1个data数据文件为主脚本分别承担训练、核函数、分类器与可视化等环节数据文件提供iris样本整体约4KB体量轻便、便于直接运行与修改。目前已有6351人学习下载说明其在SVM多分类入门实践中具有一定参考价值。读者可据此掌握MATLAB中fitcsvm与predict的调用方式理解核函数选择、正则化参数C对决策边界的影响并通过可视化脚本观察三分类结果为特征标准化、参数调优等后续实验打下基础。1. 三分类 SVM 落地从一份源码看数据分类的完整实现拿到一份「SVM 实现数据三分类」的源码很多人第一反应是打开文件找sklearn.svm.SVC看到一行SVC(kernelrbf)就以为读完了。真跑起来才发现三分类和两分类之间隔着一整套工程细节标签怎么组织、决策边界怎么画、多分类策略选ovr还是ovo、核函数参数怎么调、结果怎么验证。这份资源解决的正是这条链路——它把支持向量机从公式落到可运行的三分类任务上包含数据生成、模型训练、边界可视化和精度评估。适合两类人刚学完 SVM 理论想找一份能跑通的代码对照理解的新手以及需要把 SVM 塞进自己分类流程、想先看一个干净参考实现的开发者。下面按「能干什么 → 怎么跑 → 怎么改」拆开讲。2. 项目结构与技术选型三分类任务的骨架长什么样2.1 目录组织与文件职责这类 SVM 三分类项目通常不会太大但文件划分能看出作者的工程习惯。一个合格的参考实现一般长这样svm-three-class/ ├── data/ │ └── generate.py # 合成三分类数据控制样本分布 ├── src/ │ ├── model.py # SVM 封装训练与预测 │ ├── visualize.py # 决策边界与散点图 │ └── evaluate.py # 混淆矩阵、精度、召回 ├── config.py # 核函数、C、gamma 等超参集中管理 ├── main.py # 串起数据→训练→评估→绘图 └── requirements.txtconfig.py单独抽出来是关键设计。SVM 的超参C、gamma、kernel对结果影响极大散落在各个文件里改起来就是血泪经验。集中管理后调参只动一个地方复现实验也方便。data/generate.py用make_blobs或make_classification造三分类数据好处是不依赖外部数据集clone 下来就能跑这对一份教学型源码很重要——读者不需要先去找数据。src/model.py负责封装visualize.py负责把二维特征下的决策边界画出来evaluate.py出指标。main.py是入口按顺序调用。这种分层不是过度设计而是让「换数据」「换模型」「换评估」三件事互不干扰。2.2 技术栈与依赖版本核心依赖就三个numpy做数组运算scikit-learn提供SVC和数据集工具matplotlib画图。没有深度学习框架没有 GPU 要求纯 CPU 跑这对想快速验证 SVM 行为的人很友好。# requirements.txt 常见内容 numpy1.21 scikit-learn1.0 matplotlib3.4版本上不用卡太死scikit-learn1.0 之后SVC接口稳定make_blobs的centers参数也一直是三分类造数据的常用入口。如果环境里已有较新版本直接装即可。注意matplotlib在无显示环境比如服务器下需要设Agg后端否则plt.show()会报错这是后面避坑章节要展开的点。2.3 三分类与两分类的本质差异两分类 SVM 只找一个超平面三分类必须处理「多个类怎么拆」。scikit-learn的SVC默认用 one-vs-oneOvO三个类会训练C(3,2)3个二分类器预测时投票。另一种是 one-vs-restOvR每个类对其余类训练一个分类器共 3 个。两者在样本量小的时候差异不大但 OvO 在类别多时训练成本增长更快。这份源码如果显式设置了decision_function_shape就是在控制输出维度ovr返回 3 列决策值ovo返回成对结果。理解这一点后面调参和解释结果才不会懵。3. 核心代码拆解数据、训练、评估三段链路3.1 合成三分类数据让分布可控数据生成是整个流程的起点。用make_blobs造三个簇通过cluster_std控制重叠程度直接决定分类难度。# data/generate.py import numpy as np from sklearn.datasets import make_blobs def build_dataset(n_samples300, n_features2, centers3, cluster_std1.2, random_state42): n_samples: 总样本数三分类下每类约 n_samples/3 n_features: 特征维度设为 2 是为了后面画决策边界 centers: 类别数固定 3 cluster_std: 簇的标准差越大类间重叠越多分类越难 random_state: 固定随机种子保证每次生成一致 X, y make_blobs( n_samplesn_samples, n_featuresn_features, centerscenters, cluster_stdcluster_std, random_staterandom_state ) return X, y这段代码的逻辑很直白make_blobs在二维平面上撒三个高斯簇返回特征矩阵Xshape 为(300, 2)和标签y取值 0、1、2。cluster_std是最值得调的参数——设成 0.5 时三类分得很开SVM 轻松到接近 100%设成 2.0 时簇互相咬合精度会掉下来正好用来观察核函数和C的作用。random_state固定后每次运行数据一样调参对比才有意义。如果换成真实数据把这段替换成load_xxx或pd.read_csv保持X二维、y一维整数标签即可后续代码不用动。3.2 SVM 训练封装核函数与超参的落点模型封装的重点不是调库而是把「选什么核、参数怎么传、训练完怎么拿支持向量」讲清楚。# src/model.py from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.pipeline import Pipeline def build_model(kernelrbf, C1.0, gammascale): kernel: rbf 处理非线性边界linear 处理近似线性可分 C: 惩罚系数越大越不容忍误分类容易过拟合 gamma: rbf 核的宽度参数scale 随特征方差自适应 return Pipeline([ (scaler, StandardScaler()), # SVM 对特征尺度敏感先标准化 (svm, SVC(kernelkernel, CC, gammagamma, decision_function_shapeovr)) ]) def train(model, X_train, y_train): model.fit(X_train, y_train) return model这里有两个设计点值得说。第一Pipeline里先放StandardScaler。SVM 基于距离和间隔特征量纲不一致时数值大的特征会主导核函数计算精度莫名其妙地差——这是新手最常翻车的地方之一。标准化后再训练结果稳定得多。第二decision_function_shapeovr让decision_function输出三列每列对应一个类的得分画决策区域时直接取argmax就能得到预测类别比处理 OvO 的成对结果省事。gammascale是scikit-learn的默认自适应策略等于1/(n_features * X.var())一般不用手调真要调从0.01、0.1、1这几个量级试。训练完可以顺手看支持向量数量model.named_steps[svm].support_vectors_.shape。支持向量越少说明模型越「精简」但也要结合精度看不能单看数量下结论。3.3 决策边界可视化把三分类结果画出来二维特征的最大好处是能画图。三分类的决策边界不是一条线而是三块区域的分界用contourf填色最直观。# src/visualize.py import numpy as np import matplotlib.pyplot as plt def plot_decision_boundary(model, X, y): x_min, x_max X[:, 0].min() - 1, X[:, 0].max() 1 y_min, y_max X[:, 1].min() - 1, X[:, 1].max() 1 xx, yy np.meshgrid( np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02) ) grid np.c_[xx.ravel(), yy.ravel()] Z model.predict(grid).reshape(xx.shape) # 每个网格点预测类别 plt.contourf(xx, yy, Z, alpha0.3, cmapviridis) plt.scatter(X[:, 0], X[:, 1], cy, cmapviridis, edgecolorsk) plt.xlabel(Feature 1) plt.ylabel(Feature 2) plt.title(SVM Three-Class Decision Boundary) plt.show()逻辑分三步先用meshgrid在特征空间铺一张网格步长0.02决定边界平滑度越小越细但计算越慢再把网格点拉平成(N, 2)送进predict得到每个点的类别最后reshape回网格形状用contourf填色。散点用真实标签y上色和背景色对比就能看出哪些点被分错。alpha0.3让背景半透明散点更清楚。如果换成三维特征这套画法要改成投影或切片二维是三分类可视化的甜点区。3.4 评估混淆矩阵比单一精度更有信息量三分类只看 accuracy 容易掩盖问题——某一类全错、另两类全对精度仍有 66%。混淆矩阵能看出具体错在哪。# src/evaluate.py from sklearn.metrics import confusion_matrix, classification_report def report(model, X_test, y_test): y_pred model.predict(X_test) cm confusion_matrix(y_test, y_pred) # 3x3行是真实列是预测 print(Confusion Matrix:\n, cm) print(classification_report(y_test, y_pred, digits3)) return cmconfusion_matrix返回 3×3 矩阵对角线是分对的非对角线是混淆。比如第 0 行第 2 列数值大说明真实类 0 被大量判成类 2这时候要回头看这两类的特征分布是否重叠严重。classification_report给出每类的 precision、recall、f1digits3控制小数位。三分类场景下如果某一类 recall 明显低优先考虑调C或换核函数而不是盲目加数据。4. 跑起来环境、入口与参数调整4.1 环境准备与依赖安装从零开始先建虚拟环境再装依赖避免污染全局包。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt装完验证一下python -c import sklearn; print(sklearn.__version__)。如果版本低于 1.0decision_function_shape行为可能有细微差异建议升级。服务器或无图形界面环境在visualize.py顶部加两行import matplotlib matplotlib.use(Agg) # 无显示环境下改用文件输出然后把plt.show()换成plt.savefig(boundary.png, dpi150)图存到本地再看。4.2 入口脚本与运行顺序main.py把各模块串起来顺序是生成数据 → 划分训练测试集 → 建模型 → 训练 → 评估 → 画图。# main.py from sklearn.model_selection import train_test_split from data.generate import build_dataset from src.model import build_model, train from src.evaluate import report from src.visualize import plot_decision_boundary X, y build_dataset(n_samples300, cluster_std1.2) X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.3, random_state42, stratifyy # stratify 保证三类比例一致 ) model build_model(kernelrbf, C1.0, gammascale) train(model, X_train, y_train) report(model, X_test, y_test) plot_decision_boundary(model, X, y)stratifyy是三分类划分时容易漏的参数。不设的话随机划分可能让某一类在测试集里样本过少评估结果波动大。设了之后训练集和测试集的三类比例与原始数据一致指标更可信。运行python main.py终端输出混淆矩阵和分类报告同时弹出或保存决策边界图。4.3 关键参数怎么调调参有优先级别一上来就网格搜索。先看数据重叠程度再动核函数最后细调C和gamma。参数作用常用取值调整信号kernel决定边界形状rbf/linear线性可分用 linear否则 rbfC误分类惩罚0.1 / 1 / 10 / 100欠拟合调大过拟合调小gammarbf 核宽度scale/ 0.01 / 0.1 / 1边界太平滑调大太碎调小cluster_std数据重叠度0.5 ~ 2.0用来构造不同难度场景实操建议先把cluster_std设 0.5 跑一遍确认流程通、精度高再设 2.0 跑一遍观察精度下降和边界变化中间值用来体会参数影响。C从 1 开始精度不够往 10、100 试出现训练精度高但测试精度掉就往回退。gamma一般保持scale除非边界明显欠拟合。5. 避坑与排查三分类 SVM 常见的五个坑5.1 精度异常低检查特征是否标准化现象模型跑完精度只有 50% 左右和随机猜差不多。原因特征量纲差异大SVM 的核函数计算被大数值特征主导间隔优化失效。解决确认Pipeline里StandardScaler在SVC之前且训练和预测走同一个 pipeline 对象。如果手动标准化测试集必须用训练集的均值和方差不能各自标准化。5.2 画图报错no display name设 Agg 后端现象在服务器或容器里运行plt.show()抛RuntimeError: Invalid DISPLAY variable。原因matplotlib默认后端需要图形界面。解决在导入pyplot之前执行matplotlib.use(Agg)并把展示改成savefig。注意use必须在import matplotlib.pyplot之前调用顺序错了不生效。5.3 三分类标签不是 0/1/2先做编码现象真实数据标签是字符串或跳号整数SVC报错或结果混乱。原因scikit-learn分类器要求标签为连续整数或可比较的类别字符串需要编码。解决用LabelEncoder把标签转成 0、1、2记录映射关系预测后再inverse_transform还原。混淆矩阵的类别顺序也要和编码后一致否则解读会错位。5.4 决策边界图空白或全一色检查网格范围现象contourf画出来一片纯色看不到分界。原因网格范围没覆盖数据分布或者predict输入形状不对。解决确认x_min/x_max基于X[:, 0]计算并留了边距grid是(N, 2)形状Zreshape 回xx.shape。步长0.02在特征范围很大时会导致网格点过多、内存吃紧可适当放大到0.05。5.5 训练集精度高、测试集崩警惕过拟合现象训练集 99%测试集 70%。原因C过大或gamma过大模型把噪声也学了进去。解决先降C比如从 100 回到 1再考虑降gamma。同时检查train_test_split是否设了stratify类别不均衡时评估本身就有偏差。三分类样本量小时可以加交叉验证cross_val_score看稳定性别只信单次划分。6. 二次开发把这份三分类 Demo 改成自己的分类器拿到这份代码后最实际的改造路径是「换数据 → 换评估 → 换模型对比」。换数据时把build_dataset替换成自己的读取逻辑保证X是二维浮点数组、y是整数标签特征维度超过 2 就把可视化改成 PCA 降维后再画或者直接跳过画图只看指标。换评估时在report里加cross_val_score(model, X, y, cv5)三分类下cv5每折样本量要够样本少于 150 时改cv3。一个具体技巧把build_model的返回值做成可切换的字典方便横向对比不同核函数。# 快速对比 linear 与 rbf 在三分类上的表现 from sklearn.model_selection import cross_val_score candidates { linear: build_model(kernellinear, C1.0), rbf_C1: build_model(kernelrbf, C1.0), rbf_C10: build_model(kernelrbf, C10.0), } for name, m in candidates.items(): scores cross_val_score(m, X, y, cv5, scoringaccuracy) print(f{name}: mean{scores.mean():.3f}, std{scores.std():.3f})这段代码的价值在于用交叉验证均值加标准差代替单次划分std大说明模型对数据划分敏感这时候单次高分不可信。改造时还要注意如果换成多分类且类别数大于 3OvO 的训练器数量按C(n,2)增长类别到 10 就是 45 个二分类器训练时间会明显上升这时候可以考虑LinearSVC配合 OvR或者换用其他多分类方案。我自己的习惯是每次改完数据或参数先跑一遍交叉验证看std再决定要不要信那个精度数字——有一次单次划分 92%、五折均值只有 78%差点把过拟合的配置当成最优解交出去。从那以后我每次调 SVM 都强制走一遍交叉验证再下结论。希望这份拆解帮到你把三分类这条链路跑通、改顺。本文还有配套的精品资源点击获取