
简介这份资源面向机器学习初学者与需要完成课程实验的开发者聚焦如何用支持向量机完成数据的三分类任务并给出可运行的MATLAB实现。压缩包共6个文件以5个m脚本和1个data数据文件为主脚本分别承担训练、分类、核函数、可视化等职责数据文件用于直接加载实验样本整体约4KB轻量便于快速跑通。资源围绕一对一策略展开将三分类拆解为多个二分类SVM并涉及核函数选择、正则化参数C等关键设置帮助读者理解从训练到预测的完整流程。目前已有6349人学习下载适合希望把SVM理论落到代码、并借助MATLAB快速验证分类效果的读者参考。1. 从一张散点图说起SVM 做三分类到底靠不靠谱手头有一份带标签的二维数据三个类别混在一起边界犬牙交错。用逻辑回归硬分准确率卡在七成上不去换决策树倒是能到九成但树一深就过拟合换个随机种子结果就飘。这种场景下SVM支持向量机往往是个被低估的选项——它靠间隔最大化找决策边界对中小规模、特征维度不高的三分类任务泛化能力经常比树模型更稳。这份资源就是一个完整的 SVM 三分类实现从数据生成、特征标准化、多分类策略OvR / OvO到核函数选择、超参调优再到决策边界可视化一条链路走通。适合两类人一是刚学完 SVM 理论、想找个能跑通的代码把公式和 API 对上号的二是手里有类似三分类小数据集、想直接拿这套流程改一改就用的。下面按“能干什么 → 怎么跑 → 怎么改”的顺序拆。2. 项目结构与技术选型为什么是 sklearn numpy 这套组合2.1 目录结构与各文件职责拿到源码包先别急着跑花两分钟把目录扫一遍后面改代码时能少走弯路。这个项目的结构是典型的“脚本 模块”混合式常见做法是这样组织的svm-three-class/ ├── data/ │ └── generate_data.py # 合成三分类数据集可复现 ├── src/ │ ├── preprocess.py # 标准化、训练测试划分 │ ├── model.py # SVM 封装含 OvR/OvO 切换 │ ├── tune.py # 网格搜索调参 │ └── visualize.py # 决策边界与混淆矩阵绘制 ├── config.yaml # 核函数、C、gamma 等参数集中管理 ├── main.py # 主入口串起全流程 └── requirements.txtdata/generate_data.py负责造数据用make_classification或make_blobs生成三个簇固定random_state保证每次跑结果一致。src/model.py是核心把SVC包了一层对外暴露fit、predict、score三个方法内部根据配置决定用 OvR 还是 OvO。config.yaml把所有超参抽出来改参数不用动代码这点在反复调参时很省事。2.2 技术栈选型sklearn 的 SVC 够不够用技术栈就三样numpy做数值运算scikit-learn提供 SVM 实现和评估工具matplotlib画图。有人会问为什么不自己手写 SMO 算法血泪经验是除非你的任务是要理解算法内部每一步否则生产或实验场景直接用sklearn.svm.SVC就够了它底层是 libsvm经过大量优化数值稳定性比手写版本高一个量级。选SVC而不是LinearSVC是因为三分类任务里类别边界往往不是线性的需要 RBF 核。LinearSVC只支持线性核且多分类默认 OvR灵活性差一截。SVC支持kernelrbf、poly、sigmoid多分类策略也能通过decision_function_shape参数控制是更通用的选择。提示SVC的复杂度随样本量增长较快样本超过几万条时训练会明显变慢这个项目定位是中小规模数据量级控制在几千条以内比较合适。2.3 多分类策略OvR 和 OvO 到底选哪个SVM 原生是二分类器三分类必须靠策略扩展。两种主流做法策略原理分类器数量k3适用场景OvR一对多每个类别 vs 其余所有3类别数少、样本均衡OvO一对一每两个类别之间训练一个3类别数多、单类样本少三分类时两者分类器数量都是 3差别不大。但 OvO 在类别数增加到 10 时只需 45 个分类器而 OvR 要 10 个——等等这里 OvR 反而更少。所以选型逻辑是类别数少用 OvR类别数多且单类样本少用 OvO。sklearn的SVC默认decision_function_shapeovr但内部多分类实际走的是 OvO只是输出时转成 OvR 形状。这个细节不注意容易在解读decision_function返回值时翻车。3. 核心模块拆解从数据生成到模型训练的关键代码3.1 数据生成与预处理标准化为什么不能省先看数据生成和预处理这段这是整个流程的地基# data/generate_data.py import numpy as np from sklearn.datasets import make_classification def build_dataset(n_samples900, n_features2, n_classes3, random_state42): 生成三分类数据集n_features2 方便后续可视化决策边界 X, y make_classification( n_samplesn_samples, n_featuresn_features, n_informative2, # 两个特征都携带类别信息 n_redundant0, # 不生成冗余特征 n_classesn_classes, n_clusters_per_class1, class_sep1.2, # 类别间距值越小越难分 random_staterandom_state ) return X, yclass_sep控制类别分离度设成 1.2 时三个簇有轻微重叠正好能体现 SVM 核技巧的价值。如果设成 3.0数据太干净什么模型都能分对看不出差异。预处理部分# src/preprocess.py from sklearn.preprocessing import StandardScaler from sklearn.model_selection import train_test_split def split_and_scale(X, y, test_size0.3, random_state42): 先划分再标准化避免测试集信息泄露到训练过程 X_train, X_test, y_train, y_test train_test_split( X, y, test_sizetest_size, stratifyy, random_staterandom_state ) scaler StandardScaler() X_train scaler.fit_transform(X_train) # 只在训练集上 fit X_test scaler.transform(X_test) # 测试集只 transform return X_train, X_test, y_train, y_test, scaler这里有个高频踩坑点先标准化再划分还是先划分再标准化正确顺序是先划分。如果在全量数据上fit_transform测试集的均值和方差就“泄露”进了训练过程评估结果会虚高。stratifyy保证划分后三个类别的比例和原始一致三分类任务里类别不均衡时这个参数很关键。3.2 模型封装SVC 的参数怎么设核心模型封装在src/model.py# src/model.py from sklearn.svm import SVC from sklearn.metrics import accuracy_score, classification_report class ThreeClassSVM: def __init__(self, kernelrbf, C1.0, gammascale, strategyovr): self.model SVC( kernelkernel, CC, gammagamma, decision_function_shapestrategy, # ovr 或 ovo probabilityTrue, # 开启后可用 predict_proba random_state42 ) def fit(self, X_train, y_train): self.model.fit(X_train, y_train) return self def evaluate(self, X_test, y_test): y_pred self.model.predict(X_test) acc accuracy_score(y_test, y_pred) report classification_report(y_test, y_pred, digits4) return acc, report三个参数最需要理解C惩罚系数越大对误分类容忍度越低容易过拟合越小间隔越宽容易欠拟合。三分类任务里从 0.1 到 100 按对数刻度试。gammaRBF 核的宽度参数越大决策边界越“弯曲”越小越平滑。设成scale时等于1 / (n_features * X.var())是 sklearn 的默认推荐值。probabilityTrue开启后训练会额外做 Platt 校准训练时间增加约一倍但能拿到概率输出。如果只需要类别标签关掉能省不少时间。3.3 网格搜索调参怎么找 C 和 gamma 的最优组合调参脚本用GridSearchCV做交叉验证# src/tune.py from sklearn.model_selection import GridSearchCV from sklearn.svm import SVC import numpy as np def tune_svm(X_train, y_train, cv5): param_grid { C: np.logspace(-1, 2, 6), # [0.1, 0.25, 0.63, 1.58, 3.98, 10, 100] gamma: np.logspace(-3, 0, 6), # [0.001 ... 1.0] kernel: [rbf, poly] } grid GridSearchCV( SVC(decision_function_shapeovr, random_state42), param_grid, cvcv, scoringf1_macro, # 三分类用 macro F1避免类别不均衡误导 n_jobs-1, verbose1 ) grid.fit(X_train, y_train) return grid.best_params_, grid.best_score_scoring选f1_macro而不是accuracy是因为三分类里如果某一类样本特别少accuracy 会被多数类主导macro F1 对每个类别一视同仁。np.logspace(-1, 2, 6)生成的是对数等距的 6 个值比np.linspace更适合扫C和gamma这种跨数量级的参数。注意网格搜索的耗时随参数组合数线性增长。上面这个网格是 6×6×272 种组合5 折交叉验证就是 360 次训练。样本量上千时单次训练可能几秒总耗时就是十几分钟。调试阶段可以先把cv降到 3参数范围缩小确认流程通了再放大。4. 跑起来环境配置与完整执行流程4.1 环境依赖与安装requirements.txt内容numpy1.21 scikit-learn1.0 matplotlib3.5 pyyaml6.0安装命令python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt版本上scikit-learn1.0 以上SVC的 API 才稳定支持decision_function_shape参数低于这个版本会报TypeError。numpy1.21 以上是为了兼容 sklearn 1.0 的编译依赖。4.2 配置文件与主入口config.yaml把所有可调参数集中管理data: n_samples: 900 n_features: 2 n_classes: 3 test_size: 0.3 model: kernel: rbf C: 1.0 gamma: scale strategy: ovr tune: enable: false cv: 5main.py串起全流程# main.py import yaml from data.generate_data import build_dataset from src.preprocess import split_and_scale from src.model import ThreeClassSVM from src.tune import tune_svm from src.visualize import plot_decision_boundary with open(config.yaml) as f: cfg yaml.safe_load(f) X, y build_dataset(**cfg[data]) X_train, X_test, y_train, y_test, scaler split_and_scale(X, y, cfg[data][test_size]) if cfg[tune][enable]: best_params, best_score tune_svm(X_train, y_train, cfg[tune][cv]) print(f最优参数: {best_params}, 交叉验证 F1: {best_score:.4f}) cfg[model].update({k: v for k, v in best_params.items() if k ! kernel}) clf ThreeClassSVM(**cfg[model]).fit(X_train, y_train) acc, report clf.evaluate(X_test, y_test) print(f测试集准确率: {acc:.4f}) print(report) plot_decision_boundary(clf.model, X_test, y_test, scaler)执行python main.py终端会打印分类报告同时弹出一张决策边界图。三分类的决策边界图能看到三条边界线把平面切成三个区域RBF 核的边界是曲线线性核是直线对比着看很直观。4.3 输出解读分类报告里看什么classification_report输出每个类别的 precision、recall、f1-score 和支持度。三分类任务重点看两处一是 macro avg 的 f1反映整体均衡表现二是哪个类别的 recall 明显偏低说明这个类被模型“忽略”了可能需要调class_weight或增加该类样本。如果某个类别 support 只有个位数指标波动会很大这时候看指标不如直接看混淆矩阵。5. 避坑与排查三分类 SVM 最容易翻车的五个点5.1 标准化顺序搞反评估结果虚高现象测试集准确率 0.98换一组数据掉到 0.75。原因在全量数据上做了fit_transform再划分测试集统计量泄露。解决严格按“先划分再在训练集上 fit测试集只 transform”的顺序preprocess.py里已经这么写了改代码时别图省事合并。5.2 gamma 设成固定大值决策边界过拟合现象训练集准确率 1.0测试集 0.6。原因gamma手动设成 10 这种大值每个样本的影响半径极小模型把每个训练点都围了一圈。解决用gammascale或auto或者在对数空间搜索。判断方法是画决策边界如果边界碎成一块块小区域就是 gamma 太大。5.3 OvO 模式下 decision_function 形状对不上现象调用decision_function返回的数组形状和预期不符报维度错误。原因decision_function_shapeovo时返回的是每对分类器的投票值形状是(n_samples, n_classes*(n_classes-1)/2)三分类就是 3 列ovr时是(n_samples, n_classes)。解决统一用ovr或者在使用返回值前先打印shape确认。5.4 probabilityTrue 拖慢训练且概率不可靠现象开启概率输出后训练时间翻倍且predict_proba的值集中在 0.5 附近。原因Platt 校准在小样本上不稳定且额外训练了校准参数。解决如果只需要类别标签关掉probability如果确实需要概率确保样本量足够每类至少几百条并考虑用CalibratedClassifierCV做更规范的校准。5.5 类别不均衡时 accuracy 误导选型现象三个类别样本量 800/100/100模型把所有样本预测为第一类accuracy 仍有 0.8。原因accuracy 被多数类主导。解决评估指标换成f1_macro或balanced_accuracy训练时设class_weightbalanced让 SVM 对少数类施加更大惩罚。6. 二次开发换数据、换核函数、加新类别的改造思路拿到这套代码最常见的改造是换自己的数据。把data/generate_data.py里的build_dataset替换成pd.read_csv读你的 CSV确保X是二维数组、y是整数标签即可其余流程不用动。如果特征维度超过 2visualize.py里的决策边界画不了常见做法是用 PCA 降到 2 维再画或者直接跳过可视化只看分类报告和混淆矩阵。换核函数是另一个高频需求。config.yaml里kernel改成poly时需要额外加degree参数默认 3多项式核在特征有明确交互含义时比 RBF 更可解释。改成linear时gamma参数失效C的作用变成控制间隔宽度这时候调参范围可以缩小到[0.01, 0.1, 1, 10]。加第四个类别时SVC本身支持多分类不用改模型代码但要注意两点一是classification_report的target_names要同步更新否则标签显示成数字不好读二是 OvO 策略下分类器数量从 3 变成 6训练时间增加如果样本量大要考虑换LinearSVC加OneVsRestClassifier的组合。验证改造是否成功我一般会强制走一遍这个检查清单检查项方法通过标准数据泄露确认标准化只在训练集 fit测试集指标不异常高于训练集标签对齐打印np.unique(y)和target_names数量和顺序一致过拟合对比训练集和测试集 F1差距在 0.1 以内类别均衡看混淆矩阵对角线没有某类 recall 为 0最后说个习惯每次改完参数或数据我都会先把random_state固定跑三遍确认结果可复现再换三个不同的random_state看指标波动范围。如果波动超过 0.05说明模型对数据划分太敏感这时候调参的收益远不如增加数据或做特征工程。从那以后我每次动 SVM 的超参之前都强制先跑一遍这个稳定性检查省得在噪声上白费功夫。希望帮到你。本文还有配套的精品资源点击获取