尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

MATLAB中SVM分类与回归实战:fitcsvm与fitrsvm从入门到调参

发布时间:2026/9/25 2:53:18

资讯中心
01
ARTICLE

MATLAB中SVM分类与回归实战:fitcsvm与fitrsvm从入门到调参

MATLAB中SVM分类与回归实战:fitcsvm与fitrsvm从入门到调参
最近这段时间我一直在 MATLAB 里折腾支持向量机SVM越用越觉得这玩意儿是真的分类回归两开花。很多朋友一听 SVM脑子里浮现的全是拉格朗日对偶、KKT 条件、核函数映射这些公式还没写代码就先被劝退了。但真到实战里MATLAB 的统计与机器学习工具箱早就把 SVM 封装得服服帖帖——分类用 fitcsvm回归用 fitrsvm输入输出全是标准矩阵上手成本比想象中低得多。这篇文章不聊虚的直接用实际代码说话所有代码我都按换个数据就能跑的标准来写你把数据整理成规定的格式剩下的基本都是复制粘贴。适合正在做课程设计、写毕业论文、或者第一次在 MATLAB 里落地 SVM 的读者也适合那些已经在用 Python sklearn、想对比一下 MATLAB 方案的同行。1. 为什么在 MATLAB 里折腾 SVM分类和回归的底层逻辑其实是一套1.1 SVM 到底在干什么用掰开两堆豆子来理解支持向量机的核心思想往简单里说就是在一个高维空间里找一个超平面把不同类别的样本分开并且让这个分界面对两侧样本的安全距离最大。这个安全距离的专业术语叫几何间隔。离分界面最近的那几个样本点就是支持向量整个模型的参数其实只由这几个点决定其他样本再多也不影响决策边界的形态——这也是 SVM 在小样本场景下依然能打的原因之一。分类问题SVM 干的是找边界。回归问题呢SVM 回归SVR的思路是反过来的它不是找一个分界面而是找一个能包住大多数样本点的带状区域落在带子外面且离真实值差得远的点越少越好。这个带子的宽度由 epsilon 参数控制带子越宽模型越宽松拟合越粗糙带子越窄模型越较真越容易过拟合。理解这一点你就能明白为什么说分类回归两开花——分类是找边界回归是找带子但底层的优化框架、核函数、支持向量机制完全是同一套。在 MATLAB 里学会了 fitcsvm再去学 fitrsvm你会发现参数全是熟面孔KernelFunction、BoxConstraint、Standardize 都能复用。我甚至建议初学者把这两个函数当成一个函数的两种用法来学效率会高很多。1.2 为什么是 MATLAB 而不是自己写或换 Python有人会问SVM 不是 Python 的 sklearn 里也有吗为什么要折腾 MATLAB这个问题我在论坛上见过无数次。认真回答的话我不是想做技术选型 PK而是想说明什么场景下 MATLAB 这套方案更适合你。第一语法和矩阵思维一致。MATLAB 的 fitcsvm/fitrsvm 输入输出都是矩阵和你前面做的特征提取、数据处理天然衔接从 Excel 或者数据库读进来的表格稍微整理一下格式就能喂给模型。第二可视化方便。二维数据可以直接画出决策边界、支持向量和交叉验证的误差曲线论文里要图有图要分析有分析。第三和 MATLAB 生态配合紧密。比如你在做信号处理、图像特征提取、Simulink 仿真前面跑出一堆特征矩阵后面顺手接一个 SVM 分类器全程不用离开 MATLAB 环境。当然如果你的场景是生产环境部署、数据量上千万行Python 生态可能更合适。但在典型的小样本科研场景——比如几百到几千条样本的特征分类——MATLAB 的 SVM 完全够用而且省事。我在实际项目里测过二维数据上从读数据到画出决策边界十分钟内绝对能完成这个速度对于想快速验证想法的人来说太重要了。2. 分类实战fitcsvm 训练一个开箱即用的二分类器2.1 数据准备什么样的数据才能直接喂给 fitcsvmfitcsvm 对输入数据的要求非常规整特征矩阵 X 必须是 n×p 的数值矩阵n 是样本数p 是特征数标签 Y 可以是 n×1 的数值向量、categorical 向量或 cell 数组。我最常遇到的两个坑一是 X 不是 double 类型从 table 读进来的数据要先 table2array 转换二是字符串标签没有转 categorical导致后面的绘图、交叉验证、混淆矩阵操作各种报错。为了让你快速跑通我先写一段生成人造数据的代码。这段代码生成两个二维高斯簇一个类别是 1一个是 -1正好适合演示二分类rng(42); % 固定随机种子结果可复现 % 类别1均值 [2, 2]类别2均值 [-2, -2] X1 randn(100, 2) 2; X2 randn(100, 2) - 2; X [X1; X2]; Y [ones(100, 1); -ones(100, 1)]; figure; gscatter(X(:,1), X(:,2), Y, rb, o); legend({类别 1, 类别 -1}); title(人造二分类数据);这段代码跑完你就能看到两堆豆子分布在坐标轴两侧。注意 rng(42) 这行别删随机种子不固定你每次跑出来的数据分布都不一样写报告时连自己都没法解释结果是怎么来的。如果你手里有现成的 UCI 二分类数据集也可以直接替换这里的 X 和 Y只要保证 X 是数值矩阵、Y 是标签向量就行。2.2 训练、预测与准确率评估的标准代码数据准备好了训练模型其实就是一行调用mdl fitcsvm(X, Y, ... KernelFunction, rbf, ... Standardize, true, ... BoxConstraint, 1);解释一下几个关键参数。KernelFunction 指定核函数rbf 是高斯径向基核也是目前最常用的默认选择适合大多数非线性可分的数据Standardize 设为 true让 MATLAB 在训练前自动把每个特征缩放到均值为 0、方差为 1这个设置强烈建议开启原因我后面会单独讲BoxConstraint 控制决策边界对误分类样本的容忍程度值越大越严格、越容易过拟合值越小越宽松、越容易欠拟合先用默认的 1 起步就好。训练完成后对测试集进行预测% 生成测试集 Xtest [randn(50, 2) 2; randn(50, 2) - 2]; Ytest [ones(50, 1); -ones(50, 1)]; [label, score] predict(mdl, Xtest); accuracy sum(label Ytest) / length(Ytest) * 100; fprintf(模型在测试集上的准确率%.2f%%\n, accuracy);这里的 score 是每个样本到决策边界的分数绝对值越大说明模型对这个样本的分类越有把握。二分类里 label 的符号就是根据 score 的符号决定的。如果你想把模型保存下来以后复用直接 save(svm_model.mat, mdl)下次 load 进来就能继续 predict。另外提醒一句上面只是测试集评估还不是严格的模型验证。真正可靠的评估方式是后面要讲的交叉验证。别在调参阶段就只盯着测试集上的一次准确率那很容易被你自己的随机性骗到。如果你的标签有好几个类别fitcsvm 本身的二分类就不够了这时候用 fitcecoc 包一层它会把多分类问题拆成多个二分类 SVM 组合用法和 fitcsvm 几乎一样预测时直接 predict(fitcecoc_mdl, Xtest) 就行。2.3 画出决策边界论文和汇报都靠这张图模型训练完光看准确率不够直观尤其在做二维数据演示时把决策边界画出来才是论文和汇报的点睛之笔。做法是在特征空间里铺一张网格对每个网格点调用 predict然后按分数填色。h 0.1; [x1Grid, x2Grid] meshgrid(min(X(:,1))-1:h:max(X(:,1))1, ... min(X(:,2))-1:h:max(X(:,2))1); xGrid [x1Grid(:), x2Grid(:)]; [~, scores] predict(mdl, xGrid); scores reshape(scores(:,2), size(x1Grid)); figure; contourf(x1Grid, x2Grid, scores, [-1 0 1], LineWidth, 2); hold on; gscatter(X(:,1), X(:,2), Y, rb, o); title(SVM 决策边界与支持向量);注意这里取的是 scores 的第二列。在 fitcsvm 的二分类输出里predict 的第二个返回值是 n×2 的矩阵第一列是归为第一个类别的分数第二列是归为第二个类别的分数。你要是换了一个数据集记得先用 mdl.ClassNames 确认哪个类别排在第二列别想当然认为它就是正类。画完这张图你就能直观看到两类样本被一个弯曲边界分开也能大致判断边界有没有被个别离群点带偏。3. 回归实战fitrsvm 预测连续值别再用线性拟合硬扛3.1 fitrsvm 和 fitcsvm 的关系一套框架两种任务SVM 回归的英文缩写是 SVRMATLAB 里对应的训练函数是 fitrsvm。它的思路我在开头讲过找一个包住大多数样本的窄带子来拟合数据而不是像线性回归那样追求最小化所有点到直线的距离。这个差异在数据存在明显非线性、甚至带噪声尖峰时非常有用——线性回归会被几个离群点拖得很痛苦SVR 则因为带宽兜底对局部异常没那么敏感。核心参数是 Epsilon也就是带子的半宽。Epsilon 越大带子越宽落入带子外部的点越少模型越平滑Epsilon 越小带子越窄模型会拼命去贴合每一个点过拟合风险直线上升。MATLAB 还支持 nu-SVR 变体对应参数是 Nu它不直接指定带子宽度而是指定带子外样本占比的上限在输出范围不稳定的场景下更合理。对多数人来说先用默认的 epsilon-SVR 起步不要一上来就折腾 Nu。如果你的样本量非常小比如只有几十个仿真样本SVM 回归依然能用但这时候我会更推荐高斯过程回归这类自带置信区间的方法——这是另一个话题了。SVM 的强项在于适度规模数据下的稳定性和可解释性。3.2 完整案例预测一个波动数据的连续值假设现在有一个包含两个特征 X 和一个连续目标 y 的数据集特征和目标之间存在非线性关系。为了演示我构造一个带噪声的正弦二次混合数据rng(123); X rand(500, 2) * 4 - 2; % 两个特征范围 [-2, 2] y sin(X(:,1)) 0.5 * X(:,2).^2 randn(500, 1) * 0.2; % 训练 SVR 模型 mdl fitrsvm(X, y, ... KernelFunction, rbf, ... Standardize, true, ... Epsilon, 0.1, ... BoxConstraint, 1);训练完之后预测和评估也很直接y_pred predict(mdl, X); SS_res sum((y - y_pred).^2); SS_tot sum((y - mean(y)).^2); R2 1 - SS_res / SS_tot; RMSE sqrt(mean((y - y_pred).^2)); fprintf(R2 %.3f, RMSE %.3f\n, R2, RMSE);R2 越接近 1说明模型解释的方差比例越高RMSE 直接反映误差的绝对大小。跑这段代码你大概率会得到一个 0.9 左右的 R2因为生成的数据信噪比本身就比较高。换到你的真实数据上重点不是追求数值好看而是看模型有没有把趋势学出来——先画一张 y 和 y_pred 的散点图如果点基本分布在对角线附近说明拟合质量不错如果点形成一条弧线大概率存在某个非线性关系没被模型学到。3.3 分类和回归共用的参数速查表既然说两开花我干脆把 fitcsvm 和 fitrsvm 里重复出现的参数做一次对照整理。这张表我平时会直接存在代码注释里新写脚本前扫一眼省得每次都要翻文档。为什么要做对照因为很多参数在两个函数里含义相同但默认值微调比如 BoxConstraint 在分类里默认 1在回归里默认也是 1但回归任务往往需要更大的范围来适应连续值的波动理解这一点能帮你更快地定位模型表现不好的原因。参数fitcsvm分类fitrsvm回归我的默认建议KernelFunction核函数选择核函数选择先试 rbf线性可分再考虑 linearStandardize自动标准化特征自动标准化特征一律置 trueBoxConstraint误分类容忍度误差容忍度分类从 1 开始回归可以放宽到 10KernelScale核函数宽度缩放核函数宽度缩放交给自动寻优别手填Epsilon无回归带半宽0.1 起步看 RMSE 再调OptimizeHyperparameters自动调参开关自动调参开关auto 直接开跑需要提醒的是表格里的默认建议只是经验起点不是金科玉律。具体到你的数据一定要以交叉验证的结果为准。当你发现模型过拟合时优先动的是 Standardize 和 BoxConstraint 这两行当你发现模型太粗糙、预测值落在一个狭窄区间时先调小 Epsilon 再看看。这个先调哪个参数的判断逻辑比记住参数本身更重要调参不是玄学按照反馈方向逐步调整效果会比瞎试好得多。4. 换数据就能跑的通用骨架数据清洗、交叉验证与自动寻优4.1 数据清理三步走缺失值、量纲、类别标签真实场景的数据远没有人造数据那么干净。我总结了一个换数据就能跑的预处理三步走照着做大部分数据集都能顺利喂给 SVM。第一步处理缺失值。MATLAB 里最常用的是 fillmissing对数值特征用 linear 插值填充通常效果不错类别特征可以用 previous 或 nearest。但要注意如果某个特征缺失比例超过 30%与其硬填不如直接删掉那列否则填充出来的东西纯属噪音。第二步量纲统一。这一步可以直接交给模型里的 Standardize 参数但如果你要在训练前做特征筛选也可以先用 zscore 手动标准化具体原因后面单独讲。第三步类别标签规范化。建议统一成 categorical 类型后续画图、算指标、做分层交叉验证都更直观。% 假设 T 是读进来的 table最后一列是标签 T removevars(T, {id, 姓名}); % 删掉不参与建模的列 T rmmissing(T); % 快速删除含缺失数据的行 X table2array(T(:, 1:end-1)); % 特征矩阵 Y categorical(T{:, end}); % 类别标签如果特征数量特别多比如几百维建议先用 Lasso 或相关性分析做一轮预筛选把明显无关的特征去掉。SVM 在高维下不是不能跑但冗余特征会放大 KernelScale 的调参难度训练时间也跟着上去划不来。4.2 交叉验证别拿同一份数据自己夸自己很多新手最容易犯的错误拿全部数据训练再用同一批数据算准确率然后兴奋地觉得准确率 98%。这个数字毫无意义因为模型已经把训练样本背下来了。正确做法是交叉验证——把数据分成若干折轮流拿一折当验证集其余当训练集最后把各折误差合并。MATLAB 里第一种做法是训练时直接指定交叉验证折数cvmdl fitcsvm(X, Y, ... KernelFunction, rbf, ... Standardize, true, ... CrossVal, on, ... KFold, 5); kfold_loss kfoldLoss(cvmdl); accuracy_cv 1 - kfold_loss; fprintf(5 折交叉验证准确率%.2f%%\n, accuracy_cv * 100);第二种做法更灵活适合需要自定义划分方式时使用比如分层抽样、留一法cvp cvpartition(Y, KFold, 5, Stratify, true); accuracy_folds zeros(cvp.NumTestSets, 1); for i 1:cvp.NumTestSets trainIdx training(cvp, i); testIdx test(cvp, i); mdl_fold fitcsvm(X(trainIdx,:), Y(trainIdx), ... KernelFunction, rbf, Standardize, true); pred_fold predict(mdl_fold, X(testIdx,:)); accuracy_folds(i) sum(pred_fold Y(testIdx)) / nnz(testIdx); end fprintf(平均交叉验证准确率%.2f%%\n, mean(accuracy_folds) * 100);注意这里我加了 Stratify, true它是分层抽样保证每一折里各类别比例和总体一致。处理类别不平衡数据时尤为重要忘了设置很容易让某一折完全缺少某个类别那一折的验证结果就完全失真了。4.3 超参数自动寻优让 MATLAB 替你调参说到调参我强烈建议不要手动去试几十组 BoxConstraint 和 KernelScale 的组合太浪费时间。MATLAB 在 fitcsvm 和 fitrsvm 里都内置了贝叶斯优化自动调参用起来极其简单mdl fitcsvm(X, Y, ... OptimizeHyperparameters, auto, ... HyperparameterOptimizationOptions, struct(... AcquisitionFunctionName, expected-improvement-plus, ... MaxObjectiveEvaluations, 30, ... KFold, 5));这段代码会让 MATLAB 自动搜索 BoxConstraint、KernelScale 等关键超参数的最优组合。默认搜索 30 次目标评估通常 20 到 30 次就能收敛到不错的区域。跑完后命令行会打印每次搜索的结果最后给出优化后的最小分类误差。如果你是刚接触 SVM我建议先跑一遍 auto 寻优把自动找到的超参数当作合理的起点再做细调。对 fitrsvm 也是一样的玩法把 OptimizeHyperparameters 设为 autoMATLAB 会自动把 Epsilon、BoxConstraint、KernelScale 一起优化掉。唯一要注意的是运行时间数据量几千条时还能接受如果上万条、特征又很多30 次贝叶斯寻优可能要跑很久建议先把 MaxObjectiveEvaluations 调小到 15再逐步增加。5. 踩坑记录标准化、核函数与类别不平衡这三件事决定成败5.1 不 Standardize高量纲特征直接把核函数带偏这是我踩过最深的坑。SVM 是基于距离和高维空间度量的算法如果某个特征数值范围特别大比如收入从 3000 到 100000另一个特征只有 0 到 1那么收入特征会完全主导核函数的计算另一个特征几乎不起作用。模型学到的就是只看收入说话的假把式泛化能力自然好不到哪里去。解决办法就是 Standardize。这里有个细节值得重点说Standardize 是在训练时对每个特征独立做 z-score 标准化即减均值除以标准差。预测时 MATLAB 会记住训练集的均值和标准差并自动用它们去标准化测试集——你在做推理时绝对不能手动再标准化一遍测试数据否则模型的内部标准就对不上了。有同事手动预处理数据时把训练集和测试集分别标准化模型表现直接崩盘查了半天才发现是两边的 mu 和 sigma 不一致。如果你更想自己掌控预处理流程可以这么写mu mean(Xtrain); sigma std(Xtrain); Xtrain_norm (Xtrain - mu) ./ sigma; Xtest_norm (Xtest - mu) ./ sigma; % 关键用的是训练集的 mu 和 sigma注意训练集和测试集必须共享同一套标准化参数。任何把测试集单独标准化的操作都会让模型推理结果失真。5.2 核函数选错的代价rbf 不是万能线性也别看不起默认 rbf 核确实对大多数非线性问题都有效但不代表它永远最优。当特征数量很多、样本量也大时rbf 核的 KernelScale 必须认真调否则很容易过拟合训练集而泛化不足。相反线性核虽然没有非线性拟合能力但在特征维度高、样本量足够大的场景下往往又快又准而且模型解释性更好——你可以直接看到每个特征的权重方便跟业务方解释。我的选核建议是先别急着删代码线性核快、泛化稳定rbf 核灵活、能拟合复杂边界但代价是调参难度更高。先分别跑一遍 linear 和 rbf用 5 折交叉验证的分数对比再决定用哪个。跑一次交叉验证的成本通常不高不值得在一开始就赌一个核函数。多项式核我用得比较少它适合特定形态的数据但阶数一高数值就容易爆炸不适合当默认选项。5.3 类别不平衡正样本只有 5% 时模型会把正类全部判负这个坑在医疗诊断、欺诈检测、工业质检故障检测里特别致命。之前做故障检测时就吃过亏设备故障样本只占 3% 左右SVM 默认策略被绝大多数正常样本带着走训练完看着整体准确率 97%但故障样本几乎全被放过了。所以千万别只看整体准确率要拆开看每一个类别的召回率和精确率尤其要关注少数类的召回率。fitcsvm 给的解决方案是类别权重给少数类更大的惩罚权重让它犯错的成本更高。可以这样设置mdl fitcsvm(X, Y, ... KernelFunction, rbf, ... Standardize, true, ... Cost, [0 1; 10 0]); % 假设 ClassNames 顺序为 [负类, 正类]把正类误判为负类的代价设为 10更省事的做法是在 fitcsvm 中设置 Prior把先验概率设成和真实分布一致或者用 Weights 给少数类样本加权。实测中先把类别权重调上去再配合分层交叉验证比单纯换核函数的收益大得多。如果还想进一步提升可以结合 SMOTE 这类过采样方法——那就是另一个话题了。5.4 两个常见环境小坑中文注释乱码与工具箱版本差异最后分享两个环境层面的事。一个是 MATLAB 2023 及之后版本的中文注释乱码问题通常是因为编辑器默认编码不是 UTF-8把注释里的中文变成乱码。解决方案是在预设里把文件编码改成 UTF-8或者直接用英文注释。另一个是版本差异一些老版本没有 fitrsvm 和 OptimizeHyperparameters我记得 R2015b 之后才有 fitrsvm如果学校机房还是更老版本执行之后会直接报 Undefined function。写代码前先跑一下 ver(Statistics) 看工具箱版本能省掉很多不必要的折腾。最后说点心里话。经常有人问我SVM 是不是已经被 xgboost、随机森林这些新算法淘汰了我的看法是在小样本、特征维度适中的场景里SVM 依然是那个最不容易翻车的老伙计。它在 MATLAB 里给我的最大感受是从数据到结论的路径极短——前面做信号处理、图像特征提取辛辛苦苦拿到特征矩阵后面用 fitcsvm 几句话就能把分类做完这种顺畅感是让人愿意继续折腾这套工具的原因。如果你刚开始接触别贪多先把 fitcsvm 跑通、画出决策边界再碰 fitrsvm最后再玩自动寻优——一个台阶一个台阶来SVM 的实用价值会在你真正拿它解决手头问题的那一刻体现出来。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。