简介支持向量机SVM在电力系统短期负荷预测中的MATLAB仿真资源面向电力预测与回归建模方向的初学者和研究人员帮助读者通过实际案例掌握SVM模型构建、数据预处理与预测效果评估。压缩包共12个文件以6个txt数据文件和4个m程序为主另含2个t数据文件整体仅24KB属于轻量级代码与样例数据集便于快速上手和反复实验兼顾教学演示与自学练习。已有752人浏览学习适合作为课程设计扩展或入门SVM回归预测的参考。资源内提供可直接运行的MATLAB脚本涵盖历史负荷数据导入、数据清洗、缺失值处理、异常值识别、训练集/测试集划分以及线性、多项式、RBF等核函数的选择与参数调整思路读者可在此基础上调整C、γ等超参数结合交叉验证评估模型泛化能力并通过MSE、MAE、R²等指标对比不同设置下的预测效果从而加深对支持向量机应用于电力短期负荷预测的完整理解。1. 支持向量机的 Matlab 仿真小样本分类问题的最稳起点做一个只有 200 个样本的二分类任务第一反应如果是堆深度学习网络那你大概率会在数据准备阶段就翻车。支持向量机SVM的 Matlab 仿真恰恰是这类小样本场景里最省心的起点不用设计网络结构不用攒大数据集fitcsvm一行命令就能拿到可解释、可导出的分类器。这个方向在信号分类、故障诊断、图像特征识别这些任务里尤其好用也是很多论文对比实验里的基线模型。这篇笔记面向想在 Matlab 里快速验证 SVM 效果的工程师和研究生从工具箱选型、数据准备、参数调优一路写到避坑记录你可以照着敲、照着改半小时内跑通第一个支持向量机 Matlab 实例。2. Matlab 里做支持向量机仿真工具箱先选对后面才省事标题里带“仿真”和“实例”说明大部分人打开 Matlab 第一件事是找现成代码。但 Matlab 里做支持向量机并不是只有一条路至少有三条常见路线摆在你面前官方统计与机器学习工具箱里的fitcsvm、App 菜单里的 Classification Learner以及学术圈流传很广的第三方 LibSVM 工具箱。选错路线的代价不是不能跑而是后面调参和部署时会多绕很多弯路。2.1 fitcsvm、分类学习器与 LibSVM三条路线怎么选路线上手门槛自定义能力适合谁fitcsvm命令行低一句命令出模型支持常用核函数与参数自定义核函数需写函数句柄要写脚本批量跑实验、要控制每个参数的人Classification Learner App最低点鼠标即可有限导出模型后可继续用命令修改快速看效果、不熟悉语法、只想先验证思路的人LibSVM第三方工具箱中需自己下载并addpath高核函数、多分类策略随便换要跟论文实验严格对齐、或者手里有历史代码的人我一般会先用fitcsvm理由很实际官方函数自带交叉验证、超参数优化和模型压缩导出这些功能在 LibSVM 里都要自己拼装。网上 svm支持向量机 python 代码一抓一大把Matlab 这边的中文资料则散见于各个技术博客多数还是老代码用的还是svmtrain这种旧接口。如果你装的是近几年的 Matlab 版本svmtrain早就被移除直接报错所以新项目一律认准fitcsvm。LibSVM 的适用场景是你需要复现某篇论文里“用 LibSVM 的特定参数组合跑出来的实验结果”这时候再去碰它否则不要给自己加戏。Classification Learner 适合完全没写过 SVM 代码的人。导入表格数据后左侧勾选 SVM右侧自动出准确率还能一键导出训练好的模型。它的弱点是自定义能力差比如你想在交叉验证里做分层采样、或者自定义类别权重App 里操作就很别扭。我的建议是用 App 快速判断题能不能做一旦决定深入马上切到命令行写脚本。2.2 用 fitcsvm 跑通第一个二分类最小可运行代码选好路线后我们直接看代码。下面这套是我常用的最小可运行模板数据是随机生成的两堆高斯点拿到手直接粘贴就能跑% 生成两类二维数据每类 50 个样本 rng(42); % 固定随机种子保证实验结果可复现 X1 randn(50, 2) [2, 2]; % 第一类以 (2,2) 为中心 X2 randn(50, 2) - [2, 2]; % 第二类以 (-2,-2) 为中心 X [X1; X2]; Y [ones(50,1); -ones(50,1)]; % 标签用 1 和 -1 % 训练支持向量机分类器 mdl fitcsvm(X, Y, ... KernelFunction, rbf, ... % 使用高斯核 KernelScale, auto, ... % 核尺度自动估算 BoxConstraint, 1, ... % 惩罚系数 C Standardize, true); % 自动做标准化 % 预测前 5 个样本 label predict(mdl, X(1:5, :)); disp(label);这段代码做了三件事生成数据、训练模型、验证预测接口。rng(42)这行很多人会删掉我建议保留因为 SVM 的结果受随机影响不大但数据生成和交叉验证的随机性会影响你对比不同参数时的判断固定种子是仿真实验的基本素养。KernelFunction是核函数选择最常用的是rbf高斯核和linear线性核RBF 能处理大多数非线性问题所以新手阶段无脑 RBF 不会出大错。Standardize设为true是让模型在内部自动标准化这比你自己手动zscore更安全具体原因在第 3 章讲。BoxConstraint就是 SVM 的惩罚系数 C默认 1控制“对分类错误的容忍度”这个参数第 4 章会重点调。2.3 预测新样本与画决策边界把仿真结果变成能看的图训练出来的模型不能只在训练集上自嗨你肯定想拿新数据来预测、顺便画个决策边界看看分类面长什么样。预测新样本的接口和 LibSVM 类似但返回结果更丰富% 构造两个新样本 newData [0, 0; 3, 3]; % 得到类别标签 label predict(mdl, newData); % 同时得到分类分数正类得分和负类得分 [~, score] predict(mdl, newData); disp(label); disp(score);注意predict的输出顺序第一个返回值是类别标签第二个是得分矩阵。二分类时得分矩阵有两列分别代表每个样本属于正类和负类的分数分数差值越大说明置信度越高。可视化决策边界是支持向量机 Matlab 仿真里最有成就感的环节做法是在二维平面上铺满网格点逐点预测再用contour画等高线% 在特征空间铺网格 [x1Grid, x2Grid] meshgrid(-4:0.05:4, -4:0.05:4); xGrid [x1Grid(:), x2Grid(:)]; % 对网格点做预测 [~, scoreGrid] predict(mdl, xGrid); scoreGrid reshape(scoreGrid(:, 2), size(x1Grid)); % 画决策边界和原始数据 figure; contour(x1Grid, x2Grid, scoreGrid, [0 0], LineWidth, 2, LineColor, k); hold on; gscatter(X(:,1), X(:,2), Y, rb, o);这段网格预测在样本量小的时候很快但如果你把步长调到0.01网格点会暴增到几十万个预测耗时也跟着涨调试阶段用0.05就足够看清形状了。决策边界画出来后你就能直观判断模型是不是过拟合边界如果弯弯曲曲地刻意把每个点都包住说明 RBF 核的尺度设得太小后面调参会频繁用到这张图。3. 支持向量机的数据准备归一化、样本划分与标签处理很多人拿到数据直接丢给fitcsvm跑完发现结果差得离谱然后开始怀疑 SVM 不行。其实支持向量机本身对数据质量极其敏感尤其是特征量纲和样本划分这两件事。这一章讲的就是我在支持向量机 Matlab 仿真里反复栽跟头的数据准备环节。3.1 特征量纲不一致是 SVM 的隐形杀手SVM 的核心计算是样本间的距离内积如果某个特征的取值范围是 0 到 1另一个特征是 0 到 10000那距离计算会被后者完全主导前一个特征等于白送。这个问题在 RBF 核函数里尤其致命因为高斯核的指数部分直接依赖样本间的欧氏距离。解决方式有两种一种是手动标准化% 手动 zscore 标准化 mu mean(Xtrain); sigma std(Xtrain); Ztrain (Xtrain - mu) ./ sigma; Ztest (Xtest - mu) ./ sigma; % 用训练集的统计量不能用测试集的另一种更省心直接在fitcsvm里加Standardize, true。我强烈建议用后者因为它会把标准化参数存在模型对象里预测新数据时自动用同一套均值和方差做变换不会出现你手动标准化时“训练集用一套参数、测试集用另一套参数”的乌龙。注意Standardize只对数值型特征生效类别特征需要先用dummyvar转成独热编码或者用onehotencode函数处理。3.2 训练集和测试集怎么划cvpartition 的正确姿势划分数据集是支持向量机 Matlab 仿真里最容易出问题的地方。很多人习惯用randperm打乱索引再切分但这样有隐患如果你的数据本身就是按类别顺序排列的比如前 50 行全是正类、后 50 行全是负类不打乱直接切分会造成训练集里只有一类样本。另一个坑是分类问题应该用分层采样保证训练集和测试集里正负类比例一致。cvpartition能同时解决这两个问题% 假设 Y 是分类标签这里用分层划分 80% 训练、20% 测试 cv cvpartition(Y, HoldOut, 0.2); idxTrain training(cv); idxTest test(cv); Xtrain X(idxTrain, :); Ytrain Y(idxTrain, :); Xtest X(idxTest, :); Ytest Y(idxTest, :);cvpartition第一个参数传标签向量它内部会按类别比例做分层采样保证训练和测试集的类别分布一致。HoldOut表示留出法0.2就是留出 20% 作为测试集。如果你要做 K 折交叉验证直接改成cvpartition(Y, KFold, 5)后面跟for循环取每一折的training(cv, i)和test(cv, i)就行。这里有个经验样本总量少于 1000 条时留出法评估的方差很大建议直接用 KFold 交叉验证别省这点训练时间。3.3 标签类型、类别不平衡与 Prior 参数标签处理是新手最容易忽略的细节。fitcsvm对标签类型很宽容数值、逻辑值、字符串元胞数组都能接受但它内部会把标签转成类别变量并且默认把第一个出现的类别当成正类。这会导致一个隐蔽问题如果你的正类样本在后半部分模型输出的score第二列对应的可能是你眼中的“负类”。我的习惯是显式指定类别顺序% 显式指定正类别避免歧义 Y categorical(Y, [1, -1], {正类, 负类}); mdl fitcsvm(X, Y, ClassNames, {正类, 负类});类别不平衡是另一个高频坑。当正负样本比例超过 1:10 时SVM 学出来的决策边界会明显偏向多数类因为错分少数类的总惩罚更小。处理方式有两类数据层面做欠采样或过采样算法层面调整fitcsvm的Prior参数% 按样本比例反推先验等价于给少数类加权 mdl fitcsvm(X, Y, Prior, empirical);Prior设为empirical表示直接用训练集中各类别的经验频率这实际上是让模型更关注少数类。更激进的做法是自己指定Prior数值比如把少数类的先验调高到 0.7。注意调整Prior之后模型输出的分数含义也会变化评估时别只盯准确率多看看少数类的召回率。4. 核函数与超参数调优把 SVM 的 3 个关键旋钮拧明白支持向量机在 Matlab 里跑通容易跑出好效果难难就难在超参数。fitcsvm默认参数能处理六成问题剩下四成必须手动调。这一章把核函数类型、BoxConstraint、KernelScale这三件事讲透。4.1 线性核、高斯核还是多项式核先看数据可分性核函数选择的本质是“你预设数据是什么形状的可分性”。线性核适合本身就线性可分的数据比如图像分类里常见的 HSV 颜色直方图特征或者文本 TF-IDF 这种高维稀疏特征线性核不仅效果不差训练速度还快一个数量级。高斯核是最通用的默认选择它对非线性边界拟合能力强但容易过拟合。多项式核需要调的参数多一个PolynomialOrder并且数值稳定性差阶数一高就爆炸我实际项目里用得很少。怎么判断该用哪个核一个可复现的判别方法是先跑线性核再看训练集和测试集的准确率差距% 先跑线性核观察过拟合程度 mdlLinear fitcsvm(Xtrain, Ytrain, KernelFunction, linear, Standardize, true); trainAcc 1 - loss(mdlLinear, Xtrain, Ytrain, LossFun, classiferror); testAcc 1 - loss(mdlLinear, Xtest, Ytest, LossFun, classiferror); fprintf(线性核训练准确率 %.2f%%测试准确率 %.2f%%\n, trainAcc*100, testAcc*100);如果线性核的训练准确率和测试准确率都很低比如都在 70% 以下说明数据在当前特征空间里线性不可分换高斯核会有明显提升。如果训练准确率 99% 但测试只有 75%说明线性模型过拟合这时候换高斯核并配合正则化调参意义也不大反而应该回头检查特征是不是选多了、要不要做降维。记住核函数只是工具特征质量才是决定准确率上限的东西。4.2 BoxConstraint 与 KernelScale 到底控制什么BoxConstraint就是 SVM 的惩罚系数 C控制模型对误分类的容忍度。C 越大模型越不愿意放过任何一个训练样本决策边界越复杂过拟合风险越高C 越小边界越平滑但可能欠拟合。默认值 1 是个中庸选择实际调参范围我会从 0.1 到 100 之间搜。KernelScale控制高斯核的宽度这个参数比 C 更敏感它决定了每个支持向量的“影响半径”。尺度越小半径越小边界越曲折容易把噪声点也圈进去尺度越大边界越平滑但可能把所有细节都抹平。这两个参数的交互效应才是调参的难点。C 大 尺度小几乎必然过拟合C 小 尺度大模型会退化成近似线性分类。所以调参时不能单独动一个参数必须组合搜索。fitcsvm的KernelScale可以设auto它会根据数据分布自动估算一个初值这个初值通常够用但你做精细调优时还是要手动指定搜索范围。4.3 用 KFold 交叉验证做网格搜索一份能直接抄的调参脚本最稳妥的调参方法是网格搜索加 K 折交叉验证。别嫌土贝叶斯优化在参数空间小的时候不一定比穷举网格快而且网格搜索结果可以复现、好解释。下面这份脚本直接抄就行rng(42); CList [0.1, 1, 10, 100]; ScaleList [0.1, 0.5, 1, 5, 10]; bestAcc 0; for C CList for s ScaleList % 训练 5 折交叉验证 mdl fitcsvm(Xtrain, Ytrain, ... KernelFunction, rbf, ... BoxConstraint, C, ... KernelScale, s, ... Standardize, true); cvmdl crossval(mdl, KFold, 5); acc 1 - kfoldLoss(cvmdl, LossFun, classiferror); if acc bestAcc bestAcc acc; bestC C; bestS s; end end end fprintf(最优C %.2f, KernelScale %.2f, 交叉验证准确率 %.2f%%\n, ... bestC, bestS, bestAcc*100); % 用最优参数重新训练并评估测试集 mdlBest fitcsvm(Xtrain, Ytrain, ... KernelFunction, rbf, ... BoxConstraint, bestC, ... KernelScale, bestS, ... Standardize, true); testAcc 1 - loss(mdlBest, Xtest, Ytest, LossFun, classiferror); fprintf(测试集准确率%.2f%%\n, testAcc*100);注意两个细节。第一crossval是在已训练的模型对象上做交叉验证它会把原始模型对象里的数据拆成 K 折重新训练 K 次所以你的mdl本身只用到了数据拆分功能真正在交叉验证里训练的是内部副本这保证了交叉验证结果的独立性。第二网格搜索里两组参数范围第一轮先粗搜确定数量级第二轮在最优值附近加密比如 C 在 10 附近最优就把 CList 改成[5, 7, 10, 15, 20]这样比一次性撒大网效率高得多。最终模型的测试集准确率应该跟交叉验证准确率接近如果差距超过 5 个百分点说明数据划分或交叉验证设置有问题先回头查第 3 章的划分逻辑。如果你不想手动写网格搜索fitcsvm还内置了贝叶斯优化mdl fitcsvm(Xtrain, Ytrain, ... KernelFunction, rbf, ... Standardize, true, ... OptimizeHyperparameters, {BoxConstraint, KernelScale}, ... HyperparameterOptimizationOptions, struct(... AcquisitionFunction, expected-improvement, ... MaxObjectiveEvaluations, 30, ... KFold, 5, ShowPlots, false));贝叶斯优化的好处是自动决定下一组参数试哪里30 次评估在几百个样本上通常几分钟跑完。但注意它带随机性同一条代码跑两次结果会略不同正式实验里我还是更信任网格搜索的结果贝叶斯优化更多的用途是快速摸清参数范围给网格搜索指路。5. 支持向量机 Matlab 仿真的避坑记录5 个让我翻过车的细节这一章是我做支持向量机 Matlab 仿真攒下的血泪经验。每一条都真实发生过每一条都能让好好的一个仿真实验突然“玄学”起来。按现象、原因、解决三个层次写清楚你对照排查即可。5.1 中文注释乱码先分清是编辑器问题还是数据问题现象用新版本 Matlab 打开旧脚本中文注释全部变成乱码运行倒是能跑但代码根本没法看。原因Matlab 在某些版本更新后默认编码策略有调整而旧脚本大多是用 GBK 编码保存的新的编辑器默认按 UTF-8 解码于是中文字符全花了。这个现象在 2023 版本相关的讨论里出现频率很高。注意区分两种乱码如果只是注释乱码不影响训练结果但如果你的标签、图例或文件名里有中文且也出现乱码那会影响数据读取和可视化输出。解决最简单的办法是在编辑器里右键选择“另存为”把文件编码改成 UTF-8。如果你要批量处理多个脚本可以直接用命令行edit打开文件后在“编辑器”选项卡里切换文件编码。我的实用建议是新项目里所有变量名、标签名一律用英文字符串中文只出现在注释里这样即使编码出问题也不会影响模型和数据。图例里的中文显示问题则在画图前设置set(gca, FontName, SimHei)或使用FontName, Microsoft YaHei。5.2 归一化泄漏训练集和测试集分开 zscore 的后果现象训练集准确率 95%交叉验证准确率也正常但一到测试集就掉到 70% 以下反复检查特征和参数都没发现问题。原因这是典型的归一化泄漏。你很可能在划分数据集之前就对全量数据做了zscore或者更隐蔽的是在划分之后对训练集和测试集分别算了各自的均值方差然后再喂给模型。SVM 训练时学习到的特征尺度是基于训练集统计量的测试集用了一套不同的尺度变换相当于特征分布被平移和缩放模型自然就废了。代码看起来没报错只是结果怎么都不对。解决要么直接依赖fitcsvm的Standardize, true让模型内部处理要么手动标准化时严格只用训练集的mu和sigma。正确的代码写法在第 3.1 节已经给过核心就一句话Ztest (Xtest - mu) ./ sigma其中mu和sigma来自训练集。养成这个习惯之后这种翻车基本绝迹。5.3 高斯核在稀疏高维特征上反而变差现象数据集特征维度高达几千而且大部分是零值比如图像处理里的 HOG 特征加词袋直方图用 RBF 核跑出来的准确率反而不如线性核训练时间还翻了好几倍。原因高维稀疏特征下样本间的欧氏距离被大量零维度稀释两个样本的“距离”很大程度上由非零维度决定RBF 核在这种空间里学到的边界并不比线性核优越。更糟的是RBF 核需要计算 N 维空间的距离稀疏结构没法利用计算量直线上升。解决遇到高维稀疏特征直接把核函数换成linear。先跑线性核如果测试准确率已经能接受就不要再纠结于非线性核。如果线性核准确率不够先做特征选择或降维常用手段是去掉方差接近零的特征列或者用 PCA 降到 50 维以内再试 RBF。这是支持向量机工程实践里最容易被忽略的经验模型不好不要赖参数先想想是不是核和特征形态不匹配。5.4 类别不平衡少数类被模型直接吞掉现象正类样本 100 条负类样本 10 条训练完模型后测试集里负类样本几乎全被预测成正类准确率还挺高因为测试集里负类本来就少。原因SVM 的优化目标是全局准确率最大化少数类贡献的惩罚项在整个损失函数里占比太小模型学到的决策边界被多数类主导少数类区域被直接吞掉。准确率这个指标在这种情况下会骗人正类准确率 98% 可能只是因为负类全猜错了。解决两步走。第一步评估指标换成少数类的召回率或 F1-score别用准确率下结论。第二步在模型层面调整Prior, empirical给少数类加权也可以直接指定Prior, [0.7, 0.3]。如果加权后效果还不够再考虑数据层面的 SMOTE 过采样Matlab 里没有内置函数可以用开源的smote实现或者手动对少数类做插值生成合成样本。我一般先调先验参数数据增强放最后因为前者代码改动最小、最可控。5.5 RBF 核在大数据集上卡死先确定要不要换核现象数据量到几万条时fitcsvm训练时间从秒级跳到分钟级十几分钟训练不完是常事GPU 也帮不上忙。原因RBF 核需要计算所有样本间的核矩阵复杂度随样本量平方增长。LibSVM 的启发式分解算法在几十万样本时还能勉强跑Matlab 官方实现更倾向于直达求解数据一大就卡住。解决先问自己一个问题这个任务真的需要非线性边界吗如果特征维度本身就高比如大于 100线性核往往已经够用果断换linear训练时间瞬间回到秒级。如果必须用非线性核可以先用kmeans做原型选择把几万条数据聚类成几千个代表点再训练或者使用fitclinear配合核化特征做近似。另外提醒一下大数据集上的交叉验证代价也很高先抽一个 5000 条的子集做参数调优确定参数后用全量数据训练最终模型这是性价比最高的策略。6. 从二分类推广到多分类与回归把 SVM 用到你自己的数据上前面五章写的都是二分类但实际项目里更多是三类以上的分类任务或者连续值预测。fitcsvm只能做二分类多分类要用fitcecoc回归要用fitrsvm。这一章把这两条路讲清楚最后落到模型导出与部署验证。6.1 多分类任务fitcecoc 怎么把二分类器组合起来多分类的常规做法是“一对一”或“一对多”组合多个二分类器Matlab 里fitcecoc封装了整个过程。注意它不能直接接收fitcsvm的调用方式要用templateSVM先定义基分类器% 定义 SVM 模板支持向量机的参数都在这里指定 t templateSVM(KernelFunction, rbf, BoxConstraint, 10, Standardize, true); % 训练多分类模型 mdlMulti fitcecoc(Xtrain, Ytrain, Learners, t, Coding, onevsone); % 预测 labelMulti predict(mdlMulti, Xtest);Coding参数指定编码策略onevsone是两两组合onevsall是每类对剩下所有类。样本类别多的时候onevsone要训练的组合数量是类别数的平方级三四十类时会很慢这时候换onevsall更划算。多分类模型同样支持crossval和kfoldLoss调参逻辑和二分类完全一致。6.2 连续值预测用 fitrsvm 做支持向量回归如果标签是连续数值而不是类别比如根据传感器特征预测设备剩余寿命SVM 的回归版本是fitrsvm% 假设 y 是连续值 rng(42); mdlReg fitrsvm(Xtrain, ytrain, ... KernelFunction, gaussian, ... BoxConstraint, 10, ... Epsilon, 0.1, ... % 回归管道的宽度 Standardize, true); yhat predict(mdlReg, Xtest); rmse sqrt(mean((yhat - ytest).^2)); fprintf(RMSE %.4f\n, rmse);Epsilon是支持向量回归特有的参数它限定了一个“管道”管道内的误差不参与损失计算。Epsilon越大模型越宽松、越平滑越小则越贴近训练数据。初始值可以设为标签标准差的十分之一左右再往两个方向搜索。回归模型的交叉验证评估用kfoldLoss时要指定损失函数常用mse。6.3 模型导出与部署验证saveCompactModel 之后必须做的一件事仿真做完、参数调完接下来就是把模型用起来。fitcsvm训练出来的模型对象里存着训练数据文件很大不适合部署。用saveCompactModel压缩保存是标准做法% 保存压缩模型体积小适合部署 saveCompactModel(mdlBest, svm_model.mat); % 加载模型 mdlLoaded loadCompactModel(svm_model.mat); % 一致性验证新旧模型对新样本的预测必须完全一致 labelCheck isequal(predict(mdlLoaded, Xtest), predict(mdlBest, Xtest)); disp([模型一致性验证通过: , num2str(labelCheck)]);加载模型后第一件事就是做一致性验证别急着一键部署。我之前吃过亏压缩后的模型在某些版本里对分类分数的计算精度有细微差异虽然标签通常不变但如果你下游逻辑里要比较分数阈值就可能踩坑。验证通过后可以用codegen针对predict接口生成 C 代码部署到嵌入式设备或上位机里这是后话了。如果你要把模型结果写进论文或报告建议把第 2.3 节的决策边界图、第 4.3 节的最优参数表、以及交叉验证的混淆矩阵一起导出这三样东西比准确率数字更有说服力。我自己做支持向量机仿真的习惯是所有脚本固定rng种子、所有调参过程记录日志、所有模型导出后立即做一致性验证。这套流程看起来繁琐但能帮你省下大量“复现不出来”的后悔时间。希望帮到你。本文还有配套的精品资源点击获取
