简介:基于改进粒子群优化最小二乘支持向量机(LSSVM)的短期电力负荷预测MATLAB实现,配备可视化GUI界面,主要面向计算机、电子信息工程、数学等专业的大学生,适用于课程设计、期末大作业和毕业设计场景,也适合刚接触预测建模的MATLAB新手。压缩包共包含38个文件,以19个.m源码文件为骨架,覆盖粒子群初始化、适应度计算、LSSVM训练与预测等核心流程;同时提供3个.mat数据文件、Excel表格数据、GUI的.fig界面、PNG/JPG示意图以及PDF和Markdown说明文档,整体仅1.23MB,结构清晰,便于按需查看。资源已有45人学习浏览,附赠可直接运行的案例数据,在MATLAB 2014/2019a/2024a下均可运行。代码采用参数化编程,注释详细、关键参数可方便修改,替换数据即可使用;文档中还梳理了改进粒子群与LSSVM结合的思路与步骤,能帮助读者快速复现短期电力负荷预测实验,并在此基础上进行算法改进与结果分析。
1. 短期电力负荷预测的LSSVM方案:这份Matlab资源到底解决什么问题
短期电力负荷预测,就是提前把下一小时甚至未来24小时的用电负荷估出来。这事儿表面简单,真做起来全是细节:温度突变、节假日效应、不同区域的负荷曲线差异巨大,传统回归模型一遇到非线性就翻车。最小二乘支持向量机(LSSVM)把标准SVM的二次规划换成求解线性方程组,训练速度快一个量级,再用改进的粒子群优化(PSO)去搜正则化参数和核宽,在小样本场景下往往比BP网络稳得多。这份资源包正好把整条链路做完整:改进PSO寻优、LSSVM训练预测、GUI交互界面、附带的电力负荷数据,Matlab 2014到2024a都能跑,适合做课程设计、期末作业和毕业设计的读者直接替换数据跑通。
2. 从标准SVM到LSSVM:改进粒子群优化的两个关键参数与一个核心改进点
2.1 LSSVM和标准SVM的差别:一个线性方程组的距离
先说结论:标准SVM解的是带不等式约束的凸二次规划,样本量一大,SMO算法要迭代几百轮才收敛;LSSVM把不等式约束替换成等式约束,把误差平方放进目标函数,KKT条件化简之后就是解一个(n+1)×(n+1)的线性方程组,n是训练样本数。电力负荷预测这种场景,训练样本一般几百条,矩阵求逆在Matlab里就是毫秒级的事。
LSSVM用在这个场景的第一理由是快,第二理由是精度上不比标准SVM差。短期负荷数据本身噪声大,标准SVM的稀疏性优势在强噪声、小样本的负荷预测里体现不出来,反而是LSSVM的稠密解把所有样本信息都用上了,平滑性更好。代价是失去了稀疏性,预测时每个样本都要参与核函数计算,但输入维度只有几十个点,这点计算开销无所谓。
核函数上这份资源用的RBF核,公式长这样:
K(xi, xj) = exp( -||xi - xj||² / (2·σ²) )
σ就是核宽。σ选小了,核矩阵对角线突出,模型过拟合,预测曲线跟着训练集抖;σ选大了,所有样本的相似度都趋近于1,模型变成近似线性,又欠拟合。同样的道理,正则化参数γ控制经验误差和模型复杂度的平衡。γ太大,训练误差被压得很低,泛化能力下降;γ太小,模型过于平滑,跟不上负荷的突变。这两个参数就是PSO要搜的东西。
代码包里initlssvm.m的调用方式很能说明问题,这是工具箱的标准写法:
% initlssvm: 初始化LSSVM模型 % 参数依次为: 训练输入X, 训练输出Y, 类型type, % 正则化参数gam, 核宽sig2, 核函数类型 model = initlssvm(train_X, train_Y, 'f', gam, sig2, 'RBF_kernel'); % 然后直接训练 model = trainlssvm(model);参数说明:type位置的'f'表示函数回归,分类场景要改成'c';gam是γ正则化参数,是PSO第一个待优化量;sig2是σ²核宽平方,是第二个待优化量。工具箱还提供线性核、多项式核等选项,负荷预测场景基本都用RBF核,换核函数会改变模型性能,不建议新手动。
2.2 PSO为什么需要“改进”:惯性权重、学习因子和早熟问题
标准PSO的速度-位置更新公式是:
v(i,d) ← w·v(i,d) + c1·r1·(pbest(i,d) - x(i,d)) + c2·r2·(gbest(d) - x(i,d)) x(i,d) ← x(i,d) + v(i,d)
三个核心参数分别是:w惯性权重,w大粒子飞得远、全局搜索强,w小在局部精细搜索,经典做法是从0.9线性递减到0.4;c1、c2学习因子,c1把粒子拉向个体历史最优,c2拉向全局最优,一般取c1=c2=2;r1、r2是[0,1]均匀随机数,保证搜索随机性。
但只做这些,跑两三百代就会出现典型的早熟现象——种群所有粒子聚到局部最优附近,适应度不再下降。电力负荷预测的目标函数是非凸的,还有滞后效应,PSO很容易陷进某个平庸的坑。这个包里的gaijin.m主要就是处理这个问题。
常见的改进方向有三类,A同学试过之后确认这个包用的是变惯性权重加变异算子。第一是惯性权重非线性递减,不再单纯线性从0.9到0.4,而是每代根据粒子聚集程度动态调整,种群越集中w越大,把粒子重新轰散。第二是变异操作,每迭代一定代数,以一定概率对全局最优位置做一个随机扰动,强迫算法跳出局部最优。第三是用混沌序列初始化种群,让粒子初始分布更均匀,减少随机初始化带来的偶然性。
改进PSO单步迭代的核心逻辑,以gaijin.m的思路为例:
% 改进粒子群单步迭代示意 for d = 1 : dim v(i,d) = w * v(i,d) + c1 * rand() * (pbest(i,d) - x(i,d)) ... + c2 * rand() * (gbest(d) - x(i,d)); % 位置更新并限幅,防止越界导致模型参数无意义 x(i,d) = x(i,d) + v(i,d); if x(i,d) > ub(d), x(i,d) = ub(d); end if x(i,d) < lb(d), x(i,d) = lb(d); end end % 变异:每10代对gbest做一次随机扰动 if mod(iter, 10) == 0 idx = randi(dim, 1, 1); gbest(idx) = lb(idx) + rand() * (ub(idx) - lb(idx)); end这里变异概率和触发代数都可以在参数区直接改。注意变异位置如果选的是核宽σ,变异幅值太大会直接让模型变线性,PSO适应度曲线会出现尖峰——这是正常现象。适应度曲线有尖峰说明变异强度合适,如果完全平滑反而说明变异没起作用。限幅的ub和lb由用户预设,γ的搜索范围我一般设[1, 1000],σ²设[0.01, 100],太宽会浪费时间,太窄又可能漏掉最优解。
2.3 适应度函数的设计:不是只看训练误差
PSO要优化的目标函数在AdaptFunc1.m里。严格来说,这个函数应该返回交叉验证误差或者验证集误差,而不是训练集误差。很多新手把训练误差当适应度,最后训练误差低到0.001,测试误差却很大,这就是过拟合。
一个折中做法是:把历史数据切成训练段和验证段,用寻优得到的γ和σ训练,再在验证段上算MAPE,作为PSO的适应度。如果数据量太少,至少也要用最近一部分数据做验证。我实际跑负荷预测时习惯用验证集MAPE加一个小的正则项,防止PSO把γ推到极端值,你可以直接在AdaptFunc1.m里改返回值的计算方式。
3. 资源包结构拆解:九个核心文件与从数据到GUI的调用链路
3.1 文件清单与职责划分
解压之后会看到一堆.m、.fig和.xlsx文件,初次打开容易懵。按职责可以分成四组,第一组是LSSVM工具箱函数,包括initlssvm.m、trainlssvm.m、simlssvm.m、prelssvm.m、postlssvm.m、kernel_matrix.m,这六个是标准LSSVM工具箱文件,不需要改,它们的任务是从初始化到训练再到预测的完整链路;第二组是PSO相关,包括pso.m、BaseStepPso.m、gaijin.m、InitSwarm.m、AdaptFunc1.m,其中gaijin.m是改进后的迭代逻辑,AdaptFunc1.m是适应度函数;第三组是主程序和GUI,shorttime.m是命令行主程序,gui.m和gui.fig是GUI界面及回调;第四组是数据文件,data1.xlsx、1.xlsx、a23.xls是电力负荷历史数据,iris.data和woadata.mat是两个附带的小数据集,做算法验证用的。
各文件的关键职责用下面这张表概括:
| 文件 | 职责 | 是否需要修改 |
|---|---|---|
| shorttime.m | 主程序,串联数据加载、归一化、寻优、训练、预测、绘图 | 是 |
| pso.m | 标准PSO入口,调度初始化和迭代 | 一般不改 |
| gaijin.m | 改进PSO迭代核心,变异与动态权重 | 可微调 |
| AdaptFunc1.m | 适应度函数,决定PSO搜什么 | 建议改 |
| InitSwarm.m | 粒子群初始化,定义搜索边界 | 可调边界 |
| initlssvm.m / trainlssvm.m / simlssvm.m | LSSVM建模、训练、预测 | 否 |
| gui.m / gui.fig | 图形界面与回调函数 | 看需求 |
| data1.xlsx / a23.xls | 负荷历史数据 | 替换 |
3.2 主程序shorttime.m的完整调用链路
数据流是这样走的:先xlsread读入data1.xlsx,把负荷数据转成行向量;接着mapminmax做归一化,把数据压到[0,1]区间;然后pso.m开始寻优,内部循环里不断调用AdaptFunc1.m计算适应度,AdaptFunc1.m每次都会临时调用initlssvm、trainlssvm和simlssvm,相当于每一次迭代都在训练一个LSSVM模型;寻优结束后返回最优γ和σ;最后用这两个参数重新训练模型,对测试集预测,再反归一化还原真实量纲,画图。
%% shorttime.m 核心流程(节选) % 1. 加载数据 data = xlsread('data1.xlsx'); load_data = data(:, 2)'; % 第二列是负荷值,第一列是时间编号 % 2. 划分训练集和测试集,并归一化 train_len = 500; % 前500个点训练 train_data = load_data(1 : train_len); test_data = load_data(train_len + 1 : end); [train_x, ps_train] = mapminmax(train_data, 0, 1); % 3. PSO寻优,返回最优gamma和sig2 [best_gam, best_sig2] = pso(@AdaptFunc1, ...); % 参数见pso.m注释 % 4. 用最优参数训练LSSVM并预测 model = initlssvm(train_x, train_y, 'f', best_gam, best_sig2, 'RBF_kernel'); model = trainlssvm(model); predict_y = simlssvm(model, test_x); predict_y = mapminmax('reverse', predict_y, ps_train);这里train_y怎么构造是关键:如果做单步预测,train_y就是train_x向后平移一个时刻的序列;如果做多步预测,得构造输入矩阵,把前k个时刻的负荷作为特征、第k+1时刻作为标签。资源包里默认是单步滚动预测,想改多步需要自己改输入构造段。
3.3 GUI与后台脚本的配合方式
gui.fig是界面布局文件,gui.m是回调函数,两者通过Tag属性关联。运行gui.m就自动加载gui.fig并显示界面,界面上的“开始预测”按钮回调会调用shorttime.m的核心逻辑。注意老版本Matlab里GUIDE创建的项目,在2014上直接双击gui.fig就能打开编辑,但2024a开始GUIDE被逐步边缘化,新版本直接运行gui.m通常还能用,只是编辑器会提示兼容问题,不影响执行。
4. 实战运行:数据替换、参数修改与两种启动方式
4.1 替换自己的负荷数据:格式对了才能跑通
资源包附带的数据文件列结构比较简单,第一列是时间序号,第二列是负荷值。替换数据时,把data1.xlsx打开,B列全部换成你自己的历史负荷数据即可,A列时间序号可以留空,代码里只读取data(:,2)。如果数据是竖着排的Excel,时间在A列、负荷在B列,直接把data1.xlsx的B列覆盖就行。需要注意负荷数据的采样间隔要和代码里的设置一致,原包默认是小时级数据,一天24个点,如果你的数据是15分钟级的,训练集长度、预测步长都要跟着改。
单位方面,归一化会把数据压到[0,1],所以不需要关心原始数据是MW还是万千瓦时,反归一化会自动还原单位。但要注意,如果原始数据里有负值或者0,需要确认负荷不存在负值,否则mapminmax归一化后会出现超出[0,1]区间的点,某些老版本Matlab的LSSVM工具箱会产生NaN。
4.2 五个必须手动改的参数:从训练集比例到PSO搜索边界
%% 参数区,均在shorttime.m或pso.m头部 train_len = 500; % 训练集长度,根据你的数据总量调整 TEST_LEN = 48; % 测试集长度,预测未来几个时刻 N = 30; % PSO种群数量 MAX_ITER = 100; % 最大迭代次数 C1 = 2; C2 = 2; % 学习因子,一般不动 W_MAX = 0.9; W_MIN = 0.4; % 惯性权重上下限 UB = [100, 10]; % gamma和sigma2的上界 LB = [0.01, 0.01]; % gamma和sigma2的下界参数说明:train_len决定了用多少历史数据训练,数据总量小就按总量的80%来取;TEST_LEN是预测步数,做短期预测通常取24或48,代表预测未来一天或两天;N和MAX_ITER决定PSO搜索粒度和成本,N=30、迭代100次在几百条数据上大约几十秒,数据量大时可适当调小;UB和LB是关键,γ搜索上界设1000也行,但容易让PSO花大量时间在无意义的极端区域,我一般把γ上界控制在100以内,σ²上界控制在10以内,收敛快很多。
4.3 两种运行方式:命令行快跑与GUI可视化
第一种是直接运行shorttime.m,命令行窗口会打印每一代的适应度变化,跑完出三张图:训练集拟合图、测试集预测图、PSO收敛曲线图。这张收敛曲线图很关键,如果曲线最后还在下降,说明MAX_ITER不够,要加大迭代次数。
第二种是运行gui.m,界面弹出来后,点“载入数据”选xlsx文件,再点“开始预测”就会自动执行寻优和训练。GUI方式的好处是可以在界面上直接改几个核心参数,不用反复开编辑器,适合演示和给非技术背景的导师过目。注意GUI方式下,如果数据文件路径包含中文或者空格,某些老版本Matlab的xlsread会读不出来,建议路径保持纯英文。
5. 避坑与排查:数据读取、归一化、早熟和GUI跨版本的五个实操记录
5.1 数据读取类:工作路径与xlsx版本两个高频报错
现象:直接运行shorttime.m,报错提示找不到data1.xlsx。 原因:代码用的是相对路径,当前工作目录不在解压文件夹里。 解决:先cd到解压目录再运行,或者在shorttime.m顶部加一行拼接绝对路径的代码。
现象:Matlab 2014上xlsread读取xlsx文件,返回全NaN或读取失败。 原因:2014版本自带的Excel导入组件对高版本xlsx兼容性差,原资源包的xlsx可能是新版Office生成的。 解决:用Excel把data1.xlsx另存为data1.xls或data1.csv,再把代码里的文件名改掉。CSV格式通用性最好,跨版本不会出幺蛾子。
现象:数据读进来了,但load_data长度不对,训练集和测试集切分错位。 原因:xlsx里可能存在表头或空行,data(:,2)把表头字符串读成了NaN,实际数据长度比预期短。 解决:数据文件里删掉表头,或者用xlsread的第二个返回值区分数值和文本,代码里只保留数值行。
5.2 模型训练类:归一化维度、PSO早熟和过拟合
现象:预测曲线整体偏移,形状对但幅度差了好几倍。 原因:mapminmax归一化默认按行处理,输入数据是行向量,但某处代码把测试集当列向量传入,反归一化时维度错配。 解决:统一所有数据都是行向量,训练和预测时用同一个ps_train结构体做反归一化,不要重新调用mapminmax生成新的ps。
现象:PSO迭代到第几十代,适应度曲线平了,gbest再也没变过。 原因:早熟。种群聚在局部最优附近,变异算子没触发或变异概率设得太低。 解决:确认gaijin.m里的变异触发条件,把变异间隔从10代改成5代试一次,或者把w_max调回0.9让前期搜索更充分。
现象:训练集拟合误差极小,测试集误差很大。 原因:适应度函数用的是训练误差,PSO把γ推高导致过拟合。 解决:改AdaptFunc1.m,用验证集MAPE作为适应度值,验证集从训练集尾部切出一段专门做寻优评估。
5.3 运行兼容类:GUI在2024a上的三种兜底方案
现象:2024a上运行gui.m,报GUIDE相关错误,界面打不开。 原因:新版Matlab不再维护GUIDE,老版本.fig的兼容层被移除了一部分。 解决:第一优先是运行shorttime.m命令行版本,功能和GUI完全一致,只是没有可视化界面;第二是用openfig('gui.fig')手动加载fig文件再调回调函数;第三是花半天用App Designer重建一个界面,回调逻辑可以直接复用gui.m里的函数体,只是控件语法要改一下。实际课程设计场景里,命令行版跑通加个截图就足够交差,不用死磕GUI。
6. 进阶验证:用滚动回测给预测误差做“体检”
单次预测跑出来的误差好看不代表模型真的稳,负荷数据有周期性,周一和周末的负荷特性完全不同,只拿一段数据做测试很可能碰巧撞上规律性强的那几天。滚动回测是检验模型稳定性的常用手段:把历史数据按时间窗切成多段,每一段都重新训练、重新预测,最后统计多次预测的平均误差和误差波动范围。
%% 滚动回测示意:每次前进24小时,连续预测7天 horizon = 24; % 每次预测未来24小时 steps = 7; % 连续滚动7次 mape_list = zeros(1, steps); for k = 1 : steps % 训练集终点随k前进 train_end = total_len - (steps - k + 1) * horizon; train_data = load_data(1 : train_end); test_data = load_data(train_end + 1 : train_end + horizon); % 归一化、寻优、训练、预测(略去,沿用shorttime.m逻辑) [best_gam, best_sig2] = pso(@AdaptFunc1, ...); model = initlssvm(train_x, train_y, 'f', best_gam, best_sig2, 'RBF_kernel'); model = trainlssvm(model); y_pred = simlssvm(model, test_x); % 计算本段MAPE mape_list(k) = mean(abs(y_pred - test_data) ./ test_data) * 100; end fprintf('7天平均MAPE: %.2f%%\n', mean(mape_list)); fprintf('最大单日MAPE: %.2f%%\n', max(mape_list));如果7天的平均MAPE在3%以内、最大单日MAPE不超过6%,这份模型换到你的数据上就基本靠谱。如果某一天的MAPE突然飙到两位数,把当天的真实负荷曲线调出来看,大概率是遇到了节假日或者极端天气——这类异常样本应该从训练集里剔除,或者单独建一个节假日修正模型。
从那以后我每次拿到新的负荷预测资源,都强制自己先跑一轮滚动回测再下结论,单次预测的误差曲线看着再漂亮,也骗不了连续回测的统计结果。希望这篇拆解能帮你把这套LSSVM预测资源真正跑通、改造成自己的东西。
本文还有配套的精品资源,点击获取