SVM三分类实战:从原理到决策边界可视化

发布时间:2026/10/29 2:28:13
SVM三分类实战:从原理到决策边界可视化 简介这份资源面向机器学习初学者与需要完成课程实验的学生聚焦支持向量机从二分类扩展到三分类的完整实现帮助读者理解一对一策略下多个二分类器的构建与投票预测流程。压缩包共6个文件以5个m脚本和1个data数据文件为主脚本分别承担训练、核函数、分类器与可视化绘图等职责数据文件提供iris样本整体约4KB体量轻便便于快速运行与修改。已有6351人学习下载说明其在教学与练习场景中具有一定参考价值。读者可据此掌握MATLAB中fitcsvm与predict的调用方式理解核函数选择、正则化参数C对分类边界的影响并通过可视化脚本直观对比三分类决策结果为后续调参与多分类扩展打下基础。1. 从一份三分类 SVM 源码说起它到底能跑出什么手上这份资源标题很直白——SVM 实现数据的三分类。很多人第一反应是「SVM 不是二分类器吗」这恰恰是它值得拆的地方把二分类的支持向量机推到多分类中间要处理投票策略、类别不平衡、核函数参数和决策边界可视化几件事任何一环没对齐跑出来的三分类结果就会「看着能分、细看全乱」。这份源码包解决的正是这个落地问题给一份带标签的三类数据从特征标准化、模型训练、多分类策略选择到决策边界绘制走通一条可复现的链路。适合刚学完 SVM 公式、想把它真正跑起来的新手也适合需要快速搭一个三分类基线、再往上叠特征工程的熟手。下面按「先立住原理、再动手复现、最后盯住坑」的顺序拆。2. 三分类怎么从二分类长出来策略选型与数据准备SVM 的原生输出只有正负两类多分类必须靠组合策略拼出来。这一步选错后面调参全是白费功夫所以先把策略和数据这两块地基打牢再谈代码。2.1 一对多与一对一两种组合策略的取舍常见做法有两类。一对多One-vs-RestOvR是给每个类别训练一个二分类器把当前类当正例、其余全部当负例预测时取决策函数值最大的那个类。一对一One-vs-OneOvO是在每两个类别之间训练一个分类器三分类就是 C(3,2)3 个分类器预测时用投票决定归属。三分类这个规模下两种策略的计算量差别不大真正的差别在边界行为。OvR 每个分类器都面对「一类 vs 其余两类」的不平衡问题某一类样本少的时候容易被压OvO 每对分类器只比较两类单次训练样本更均衡但会出现投票平票的可能需要额外的决策函数值兜底。我一般三分类优先用 OvO因为类别数少、投票歧义可控而且 scikit-learn 的SVC默认就是 OvOdecision_function_shape参数还能在需要时切成 OvR 视角看结果。策略三分类下分类器数单次训练样本主要风险OvR3全量正负比例失衡少数类被多数类淹没OvO3仅两类较均衡投票平票需决策值兜底选型理由说清楚类别数在 10 以内、样本量中等时OvO 的训练开销和边界质量更稳类别数上去以后 OvO 的分类器数量按平方增长才轮到 OvR 或层次策略出场。这份资源是三分类OvO 是合理默认。2.2 特征标准化与标签编码别让量纲毁掉核函数SVM 对特征尺度极其敏感因为核函数算的是样本间距离或内积。一个特征量纲是千级、另一个是零点几级距离几乎完全由大尺度特征主导模型等于只学了一半信息。所以训练前必须标准化常见做法是StandardScaler做零均值单位方差或者数据有明显异常值时用RobustScaler。标签也要处理。三分类的原始标签可能是字符串比如三个类别名SVM 内部要转成 0/1/2 的整数编码预测完再映射回去。这一步用LabelEncoder最省事但要注意训练集和预测集必须用同一个编码器对象否则类别映射错位准确率会莫名其妙掉到随机水平。import numpy as np from sklearn.preprocessing import StandardScaler, LabelEncoder from sklearn.model_selection import train_test_split # X: 形状 (n_samples, n_features)y: 字符串或整数标签 le LabelEncoder() y_enc le.fit_transform(y) # 三类 - 0/1/2映射关系保存在 le.classes_ X_train, X_test, y_train, y_test train_test_split( X, y_enc, test_size0.25, stratifyy_enc, random_state42 ) scaler StandardScaler() X_train_s scaler.fit_transform(X_train) # 只在训练集上 fit X_test_s scaler.transform(X_test) # 测试集只 transform防止信息泄漏这段的关键在最后两行fit_transform只对训练集做测试集一律transform。很多人图省事对全量数据先标准化再切分测试集的均值方差就泄漏进了训练过程评估结果虚高上线就翻车。stratifyy_enc保证切分后三类比例一致三分类样本本来就不多的时候尤其重要。2.3 核函数与关键参数三分类场景下的起步配置三分类数据如果线性可分linear核足够且可解释如果边界弯曲rbf核是默认首选。rbf有两个核心参数C控制对误分类的惩罚越大越容易过拟合gamma控制单个样本的影响半径越大边界越紧、越容易记住训练点。起步配置我一般这样给C1.0、gammascalescikit-learn 的默认等于 1/(n_features * X.var())先跑通看混淆矩阵再决定往哪个方向调。三分类的评估不能只看准确率要看每一类的召回否则某一类全错、总体准确率还有 66% 的假象。from sklearn.svm import SVC from sklearn.metrics import classification_report, confusion_matrix clf SVC( kernelrbf, C1.0, gammascale, decision_function_shapeovr, # 训练仍是 OvO输出 ovr 形状的决策值便于分析 random_state42 ) clf.fit(X_train_s, y_train) y_pred clf.predict(X_test_s) print(confusion_matrix(y_test, y_pred)) print(classification_report(y_test, y_pred, target_namesle.classes_))decision_function_shapeovr这个参数容易被误解它不改变训练时的 OvO 机制只改变decision_function返回值的形状方便你按「一类对其余」的视角看每个类的得分。真正影响分类结果的是核函数和 C、gamma别把这两件事搞混。3. 把源码跑通训练、评估与决策边界可视化原理立住之后进入动手环节。这一章按「数据进、模型出、边界画出来」的顺序走每一步都给可抄的代码和参数说明跑完你应该能拿到一张带三类区域和测试点的决策边界图。3.1 数据加载与三类样本的构造资源里的数据可能是 CSV也可能是脚本内生成的模拟数据。不管哪种加载后先做三件事看形状、看每类样本数、看特征范围。三分类最常见的翻车是某类样本只有十几个训练时被另外两类挤没。import pandas as pd df pd.read_csv(three_class_data.csv) # 列名按实际资源调整 print(df.shape) print(df[label].value_counts()) # 每类样本数少于 30 要警惕 print(df.describe()) # 特征量纲差异一眼可见 X df.drop(columns[label]).values y df[label].values如果资源没有现成数据用make_classification或make_blobs造三类数据也能复现整条链路n_classes3、n_features2二维便于画边界、class_sep控制类间重叠程度。造数据时把class_sep调小一点能模拟真实场景里边界模糊的情况比一造就好分的玩具数据更能暴露问题。3.2 训练与交叉验证别用单次切分下结论单次 train/test 切分在三分类小样本上波动很大换个随机种子准确率能差十几个点。稳妥做法是分层 K 折交叉验证看每折的分数分布而不是单个数。from sklearn.model_selection import StratifiedKFold, cross_val_score cv StratifiedKFold(n_splits5, shuffleTrue, random_state42) scores cross_val_score(clf, X_train_s, y_train, cvcv, scoringf1_macro) print(每折 f1_macro:, np.round(scores, 3)) print(均值/标准差:, scores.mean().round(3), scores.std().round(3))这里用f1_macro而不是accuracy因为 macro 对三类一视同仁某一类表现差会直接把均值拉下来比准确率更能暴露类别不平衡的问题。标准差超过 0.05 就说明数据或参数不稳先别急着调 C回去看样本分布。3.3 决策边界可视化把三分类的「分界线」画出来二维特征的三分类最适合画决策边界一眼能看出模型是把三类分成了三块还是把两类混在一起。做法是在特征空间铺网格、逐点预测、用等高线填色再把测试点叠上去。import matplotlib.pyplot as plt # 用前两个特征画二维边界特征多于两个时先做降维或只取两维 X_plot X_train_s[:, :2] clf_2d SVC(kernelrbf, C1.0, gammascale).fit(X_plot, y_train) x_min, x_max X_plot[:, 0].min() - 1, X_plot[:, 0].max() 1 y_min, y_max X_plot[:, 1].min() - 1, X_plot[:, 1].max() 1 xx, yy np.meshgrid(np.linspace(x_min, x_max, 300), np.linspace(y_min, y_max, 300)) Z clf_2d.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape) plt.contourf(xx, yy, Z, alpha0.3, cmapviridis) plt.scatter(X_plot[:, 0], X_plot[:, 1], cy_train, edgecolork, cmapviridis) plt.title(SVM three-class decision boundary (RBF)) plt.show()网格密度 300 是清晰度和速度的折中太低边界呈锯齿太高画图卡顿。注意这里为了可视化只用前两维重新训练了一个模型它和全特征模型不是同一个别拿这张图的准确率当全特征模型的评估结果。想看全特征模型的效果还是回到 3.2 的交叉验证。3.4 参数扫描C 与 gamma 的网格怎么设三分类的调参重点在 C 和 gamma 的配合。经验上先粗后细C 取 10 的幂次、gamma 取scale附近的数量级先看哪片区域稳再在稳的区域内细化。from sklearn.model_selection import GridSearchCV param_grid { C: [0.1, 1, 10, 100], gamma: [scale, 0.01, 0.1, 1], kernel: [rbf] } grid GridSearchCV(SVC(), param_grid, cvcv, scoringf1_macro, n_jobs-1) grid.fit(X_train_s, y_train) print(最优参数:, grid.best_params_) print(最优分数:, round(grid.best_score_, 3))n_jobs-1用满 CPU 核三分类这个规模几秒就能扫完。best_score_是交叉验证均值不是测试集分数别拿它当最终指标汇报。扫完把最优参数代回 3.2 的流程在独立测试集上再验一次这一步是很多人省掉的后悔药。4. 避坑与排查三分类 SVM 最容易翻车的五处这一章是血泪经验集中区。下面五条都是三分类场景下高频出现的问题按「现象 → 原因 → 解决」写遇到对号入座即可。4.1 准确率虚高但某一类全错现象总体准确率 0.8 以上混淆矩阵里某一类的召回接近 0。原因三类样本严重不平衡OvR 或 OvO 的决策都偏向多数类加上评估只看 accuracy 掩盖了问题。解决先看value_counts()确认比例样本少的类做重采样或给class_weightbalanced评估换成f1_macro和每类召回别被总数骗了。4.2 标准化顺序错了导致测试集虚高现象交叉验证分数漂亮换一批新数据预测就崩。原因对全量数据先fit_transform再切分测试集的统计量泄漏进训练。解决严格按 2.2 的顺序fit只在训练集上做测试集和新数据一律transform把这条写进流程检查清单。4.3 标签编码在训练和预测间不一致现象模型训练时准确率正常预测新样本时类别整体错位比如把 A 类判成 C 类。原因预测时重新fit了一个LabelEncoder类别到整数的映射和训练时不同。解决编码器对象随模型一起保存joblib.dump预测时加载同一个对象做transform和inverse_transform绝不重新 fit。4.4 gamma 过大导致边界碎片化现象训练集准确率接近 1测试集明显掉决策边界图上出现一圈圈孤立的色块。原因gamma太大每个样本的影响半径过小模型把噪声也记住了。解决把gamma往scale或更小调配合交叉验证看f1_macro是否回升同时检查特征是否已标准化未标准化时gammascale的自动估计也会失真。4.5 可视化模型和评估模型不是同一个现象决策边界图看着分得很干净但交叉验证分数一般。原因画图时只取前两维重新训练评估用的是全特征模型两者本就不是一个东西。解决图只用于定性看边界形状定量结论一律以全特征模型的交叉验证和独立测试集为准汇报时把两者分开写清楚。5. 进阶把三分类 SVM 嵌进真实流程的几个技巧跑通单份数据只是起点真实项目里 SVM 三分类往往要和特征工程、模型持久化、阈值调整配合。这一章给几个我实际会用的技巧都是能直接搬进流程的。第一个技巧是特征选择前置。SVM 对无关特征不敏感是误解无关特征会稀释核函数的距离度量。三分类数据特征维度超过二十时先用方差过滤或基于模型的重要性排序砍一轮再进 SVM往往比直接调 C 和 gamma 收益大。常见做法是用SelectKBest配f_classif做粗筛保留前若干维再训练。第二个技巧是模型持久化要连预处理一起存。只存SVC对象、不存scaler和LabelEncoder上线时预处理对不上预测结果必错。稳妥做法是用Pipeline把标准化和分类器串起来整体 dump。from sklearn.pipeline import Pipeline import joblib pipe Pipeline([ (scaler, StandardScaler()), (svc, SVC(kernelrbf, C1.0, gammascale, class_weightbalanced)) ]) pipe.fit(X_train, y_train) # 注意Pipeline 内部自己管标准化传原始特征 joblib.dump({model: pipe, encoder: le}, svm_three_class.pkl) # 预测时 bundle joblib.load(svm_three_class.pkl) y_new bundle[encoder].inverse_transform( bundle[model].predict(X_new_raw) )用Pipeline之后标准化参数跟着模型走新数据进来直接喂原始特征少一个手工对齐的环节就少一类翻车。class_weightbalanced在这里顺手加上三分类不平衡时能兜一层。第三个技巧是决策值阈值微调。三分类里如果某一类的误判代价明显更高比如漏检比误检贵不要只信predict的硬分类用decision_function拿三类得分对目标类设一个偏低的相对阈值牺牲一点总体准确率换目标类召回。这个操作要在验证集上定阈值再拿到测试集确认别在测试集上反复试。第四个技巧是核函数选择的验证方法。linear和rbf谁更好不要凭感觉用同一套交叉验证各跑一遍比f1_macro均值和标准差差距在标准差以内就选linear可解释性和预测速度都更好。三分类数据线性可分程度高的时候linear经常不输rbf还省了调gamma的功夫。最后说个验证习惯。我每次交付一个三分类 SVM 之前会强制走一遍「混淆矩阵 每类召回 独立测试集 新样本单条预测」四步尤其是最后一步——拿一条手工构造的新样本走完整预测链路确认编码、标准化、预测、反编码四段都对得上。这一步救过我两次都是编码器没随模型保存导致的类别错位交叉验证完全看不出来。希望这套流程帮到你少走我踩过的弯路。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询