
简介电力负荷的短期与未来时段预测是电力系统运行与能源调度中的关键任务。资源内含一套基于深度学习的Python实现方案涵盖Transformer、LSTM、GRU等时序模型并引入ARIMA、决策树、KNN、随机森林等对比算法代码附有详细注释。适用于计算机、数据科学、人工智能、通信、物联网等专业的学生开展课程设计、毕业设计或初期项目演示也适合算法初学者从数据预处理到模型评估完整跟进。资源包共20个文件包括16个Python脚本、2个说明txt和2个Markdown文档整体大小约43KB说明文档交代项目结构与运行环境Python脚本按数据预处理、模型训练、预测与评估等模块组织便于按需查阅。目前已有266人学习下载。项目经过完整功能验证可稳定运行详细的注释和清晰的模块划分既便于逐步理解电力负荷预测原理也支持替换数据集、扩展新模型进行二次开发与个性化改进。1. 电力负荷的时间序列未来预测为什么这份源码值得拿来就用电力负荷预测是电网调度、购电计划、售电公司现货报价、楼宇能源管理共同依赖的底座。你拿到的这份标题为《基于深度学习算法实现电力负荷的时间序列未来预测 python 源码 (有详细注释.zip》的压缩包本质上是把「历史负荷曲线 → 未来一段时间的负荷值」这件事用深度学习时间序列预测模型做成了可以复现的工程项目。适合三类人刚入手深度学习时间序列预测、想找完整 python 训练链路当模板的开发者电网侧、园区侧要做短期负荷预测但不想从零造轮子的数据工程师以及正在做课程设计、毕业设计需要一份能跑通、能讲清原理的源码作参照的学生。它的价值不在于模型多新而在于样本怎么构造、数据怎么归一化、预测结果怎么反算回物理量这些坑已经被填平了。2. 负荷预测先想清楚特征、粒度与训练窗口2.1 把时间序列预测改造成监督学习滑窗样本才是核心深度学习模型不会直接「理解」时间序列它只能做有监督的映射给定一段历史窗口输出下一个或多个时刻的值。所以在写模型之前第一步一定是对原始负荷序列做滑窗把一维的时间序列变成(样本数, 窗口长度, 特征数)的三维张量。常见做法是原始数据只有timestamp和load两列滑窗后每条样本用前look_back 96个点预测后predict_steps 24个点。这里的时间粒度直接决定窗口大小如果是 15 分钟一个采样点96 个点就是一整天的历史24 个点就是未来 6 小时如果按小时采样96 个点对应 4 天历史24 个点对应未来一天。滑窗时有一个容易被忽略的细节样本之间是否重叠。如果步长step 1相邻样本只错一个点训练集膨胀得非常大模型容易过拟合如果step window样本完全不重叠数据量又太少。我一般会在工程里把step设为predict_steps的整数倍让相邻样本保留一定冗余又不至于重复度过高。对于负荷预测这种强周期数据样本数在上万级别就已经足够训练一个中等规模的 LSTM。import numpy as np import pandas as pd def create_supervised_samples(df, look_back96, predict_steps24, step8): 将电力负荷时序转换为监督学习样本。 返回 X: (样本数, look_back, 特征数), y: (样本数, predict_steps)。 data df[load].values.astype(np.float32) # 归一化放在这里之前做或在这里之后单独处理均可但要保持一致 X, y [], [] for i in range(0, len(data) - look_back - predict_steps 1, step): X.append(data[i: i look_back]) y.append(data[i look_back: i look_back predict_steps]) X np.array(X).reshape(-1, look_back, 1) # 特征为负荷本身 y np.array(y) return X, y这段代码里step8是滑动步长控制样本重叠度look_back决定模型能看到多长的历史predict_steps是未来要预测的步数。reshape(-1, look_back, 1)里的1是特征通道数如果之后要加入温度、湿度、节假日标记只需把最后一维换成n_features并在滑窗时同时截取多个特征列。很多源码里这一步被封装成DataLoader或make_sequences函数但本质都是这一个逻辑。时序预测里的「未来预测」永远是对已见历史的有条件外推滑窗做不好后面模型再花哨也白搭。2.2 特征不是越多越好时序特征工程里的加法、乘法与节假日标记关于时间序列的分解经常被问到「时间序列法乘法模型和加法模型」加法模型认为序列是趋势 季节 残差乘法模型认为序列是趋势 × 季节 × 残差。深度学习方法不需要显式选择加法还是乘法但这两个概念直接影响特征设计。负荷序列通常有明显的日周期性、周周期性还受温度、节假日影响。常见做法是把时间戳拆成hour_of_day、day_of_week、is_holiday三个特征再加一个通过滚动平均计算的趋势项。注意 one-hot 不要直接给 LSTM 用类别编码比如day_of_week6和day_of_week0不能被编码成 6 和 0 的数值距离要么做 embedding要么直接用np.sin(2 * np.pi * hour / 24)这类周期编码。周期的加法、乘法特征可以这样构造加一个is_weekend二值特征描述周内状态加一个hours_since_midnight连续特征描述日内相位。温度特征在夏季制冷负荷里非常关键但温度数据往往来自外部气象源和负荷数据采样频率不一致需要先按时间戳对齐再前向填充缺失值。我见过有人把十几个气象特征全部塞进去模型训练时间翻倍测试精度却不如只用负荷和小时数——深度学习的特征不是越多越好负荷自回归本身已经包含了大部分历史信息。2.3 模型选型LSTM、GRU 与 Transformer 怎么选电力负荷时间序列预测模型里LSTM 是使用频率最高的基线其次是 GRU 和 Transformer。选型的现实依据是训练成本和收益的平衡。GRU 比 LSTM 少一个门控参数量小收敛速度快在小样本上不容易过拟合LSTM 门控更完整对中长期依赖更稳适合 96 点以上窗口Transformer 在负荷预测上的优势是能直接捕获长距离依赖但需要更多数据且对归一化和位置编码更敏感很多入门源码不会把它作为首选。表格式对比看更清楚模型参数量适合窗口长度训练难度典型场景LSTM中24~168低单步/多步短期负荷预测GRU小24~96低数据量较小时更稳BiLSTM中大48~168中需要同时利用前后文时Transformer大168 或长序列高有大量数据且要长序列建模对大多数训练集只有几个月的数据的情况LSTM 是最好上手的起点。源码里如果直接写了 LSTM 类模型齐活如果写的是 GRU训练逻辑几乎一致。切换网络时只需要替换模型类数据管线完全不用动。这也是把数据预处理、滑窗、训练循环和模型结构解耦的价值所在。3. 跑通最小训练链路数据预处理、LSTM 模型与训练循环3.1 数据预处理的三个必做点清洗、归一化、训练集划分拿到原始负荷数据第一步不是建模而是看一眼时序曲线。电力负荷数据常见脏点包括缺失值、零值、尖峰毛刺、换表导致的跳变。缺失值我一般用前后 24 点中位数填补而不是均值因为负荷在日内波动大均值会把夜间低谷和白天高峰混在一起。尖峰毛刺用 3σ 原则检测超过均值 3 个标准差的值用前一个正常值替代。这些操作写在任何一份合格源码的preprocess.py里。归一化是时间序列预测里最容易埋雷的地方。负荷值通常是几百到几千千瓦LSTM 的激活函数对输入尺度敏感不归一化会导致梯度振荡。常见做法是MinMaxScaler或StandardScaler。注意scaler必须只fit在训练集上验证集和测试集用同一个 scaler 做 transform绝不能在整个数据集上先归一化再划分——那是典型的数据泄漏会让测试分数虚高。from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler(feature_range(0, 1)) # 只对训练部分做 fit再 transform 全部 train_size int(len(df) * 0.8) train_load df[load].iloc[:train_size].values.reshape(-1, 1) scaler.fit(train_load) df[load_scaled] scaler.transform(df[load].values.reshape(-1, 1))这里的顺序不能反过来。先划分再归一化的含义是归一化参数来自训练集测试集只是被映射到同一坐标空间如果先全量归一化再划分测试集的信息已经影响了min和max相当于模型在考试前偷看了答案。另外预测完成后要输出真实功率值记得调用scaler.inverse_transform反算。很多源码注释会把这一步单独写出来你运行时会发现预测曲线看起来贴合得很好但单位是归一化后的 0~1 区间反算后才是有物理意义的千瓦数。3.2 写一个 LSTM 负荷预测模型从定义到前向传播模型结构不需要复杂一个输入层、一个 LSTM 层、一个全连接输出层就够了。尽可能保持简洁因为负荷预测的任务不是图像识别不需要几十层的深度。下面这个PyTorch模型定义是常见做法换成TensorFlow只是语法差异逻辑等价。import torch import torch.nn as nn class LoadForecastLSTM(nn.Module): 电力负荷预测的 LSTM 模型。 input_size: 每个时间步的特征数 hidden_size: LSTM 隐状态维度 num_layers: LSTM 层数, 一般 1-2 层 output_size: 未来预测步数 def __init__(self, input_size1, hidden_size64, num_layers1, output_size24): super(LoadForecastLSTM, self).__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): # x: (batch_size, look_back, input_size) out, _ self.lstm(x) # 取最后一步的隐状态 out out[:, -1, :] # (batch_size, hidden_size) out self.fc(out) # (batch_size, output_size) return outbatch_firstTrue意味着输入张量的第一维是批次这个细节经常导致维度错误。out[:, -1, :]是在取序列最后一个时间步的隐状态它浓缩了整个窗口的信息。后面接全连接层输出一个长度为output_size的向量对应未来 24 个点的预测。如果只想预测下一步output_size改为 1 即可。隐状态hidden_size我一般取 32~128过大会让小数据集过拟合过小则拟合不了日周期这种非线性num_layers在大多数负荷数据集上 1 层就够两层以上的收益很小训练时间却成倍增加。源码注释里通常会写明这些参数的默认值你可以先跑通再逐项调整。3.3 训练循环损失函数、优化器与学习率策略负荷预测本质上是一个回归任务损失函数首选MSELoss也可以用HuberLoss对尖峰毛刺更鲁棒。优化器用Adam起步lr0.001每若干轮降低学习率。训练循环要关注的不只是 loss 下降还要监控验证集 loss防止过拟合。下面是一个完整的训练与验证骨架。model LoadForecastLSTM(input_size1, hidden_size64, output_size24) criterion nn.MSELoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size20, gamma0.5) X_train_t torch.from_numpy(X_train).float() y_train_t torch.from_numpy(y_train).float() X_val_t torch.from_numpy(X_val).float() y_val_t torch.from_numpy(y_val).float() for epoch in range(100): model.train() optimizer.zero_grad() pred model(X_train_t) loss criterion(pred, y_train_t) loss.backward() optimizer.step() if (epoch 1) % 10 0: model.eval() with torch.no_grad(): val_pred model(X_val_t) val_loss criterion(val_pred, y_val_t) print(fepoch {epoch1}, train_loss{loss.item():.6f}, val_loss{val_loss.item():.6f}) scheduler.step()StepLR每 20 个 epoch 把学习率乘以 0.5前段快速下降、后段精细收敛这个策略比固定学习率更容易压到更低的 loss。如果用 GPU 训练记得把模型和数据都.to(cuda)。训练结束后torch.save(model.state_dict(), lstm_load.pt)后续推理时再加载。这一步里最常见的报错是张量维度不匹配——X_train是三维(样本数, 窗口, 特征)但某些代码在构造 DataLoader 时把特征维度丢了传进去变成二维。遇到时就回到create_supervised_samples检查返回的 shape。4. 拿到这份 python 源码后按什么顺序读、怎么改4.1 先从目录结构判断工程的成熟度一份规范的 python 时间序列预测源码通常会把五个环节拆成独立模块数据读取、预处理、滑窗造样本、模型定义、训练评估。不需要文件名完全一致但结构应该能对上。拿到压缩包解压后我一般会先扫一眼文件清单如果全部代码都在一个几百行的main.py里说明作者把步骤串在一起了读起来费力但跑通更容易如果拆了data_loader.py、model.py、train.py、utils.py工程会更清晰也方便你只修改其中一环。重点文件清单一般长这样文件/目录典型内容修改时机data/原始负荷数据常见 csv/xlsx换成自己的数据preprocess.py缺失值填补、异常值处理、归一化改了数据格式时dataset.py滑窗构造样本、DataLoader调整 look_back / predict_stepsmodel.pyLSTM/GRU/Transformer 定义调整网络结构train.py训练主循环、验证、保存模型调整学习率、epochevaluate.py加载模型、预测、画曲线、算指标换数据集后验证效果拿到源码第一步不要去读模型定义先找数据读取部分确认它读的是什么格式、时间列是什么格式。很多源码默认数据是两列date, load但实际业务数据可能是多列或者时间戳是 UNIX 格式这里是最先要改的地方。注释详细的源码会在文件开头写明「数据格式第一列时间第二列负荷值时间格式为YYYY-MM-DD HH:MM:SS」直接按着说明准备数据即可。4.2 训练前必须确认的三个参数look_back、predict_steps、train_ratio这三个参数直接决定预测任务本身。look_back决定模型能看到多长的历史太小则看不到完整日周期太大则引入过多噪声predict_steps是最终要预测未来多少个点等于 24 通常意味着预测未来一天train_ratio是训练集占比常见 0.8 或 0.7。其中train_ratio有个容易被误解的点时间序列划分不能随机打乱必须按时间顺序切分否则模型用未来数据训练再预测过去验证分数完全失真。python train.py --look_back 96 --predict_steps 24 --train_ratio 0.8 --epochs 100命令行参数存在的意义是让你不用改代码就能反复试不同配置。如果源码里没有命令行入口就找到训练函数入口把这几个值改成你的配置。经验数值供参考15 分钟粒度的数据look_back 96覆盖一天predict_steps 96覆盖未来一天小时粒度的数据look_back 168覆盖一周predict_steps 24覆盖未来一天。日粒度数据的预测没太大工程价值因为负荷预测的粒度越细对调度的指导意义越大。4.3 训练完怎么评估别只盯着 loss要看 MAPE 和预测曲线模型的均方误差只能告诉你误差在缩小但无法直接和业务指标挂钩。负荷预测领域最常用的评估指标是平均绝对百分比误差MAPE它把误差折算成相对百分比电网调度里通常要求短期负荷预测的 MAPE 在 3%~5% 之间。另一个是RMSE它的量纲和负荷相同单位是千瓦或兆瓦能直观告诉你平均偏差有多大。import numpy as np def mean_absolute_percentage_error(y_true, y_pred): # 过滤掉真实值为 0 的点, 避免除零 mask y_true ! 0 return np.mean(np.abs((y_true[mask] - y_pred[mask]) / y_true[mask])) * 100 def evaluate_forecast(y_true, y_pred, scaler): # 反归一化后计算物理量纲的误差 y_true_inv scaler.inverse_transform(y_true.reshape(-1, 1)).ravel() y_pred_inv scaler.inverse_transform(y_pred.reshape(-1, 1)).ravel() mape mean_absolute_percentage_error(y_true_inv, y_pred_inv) rmse np.sqrt(np.mean((y_true_inv - y_pred_inv) ** 2)) return mape, rmse看评估结果时不要只看整体 MAPE要把预测曲线和真实曲线画在同一张图上。负荷曲线有典型的早高峰和晚高峰如果模型在峰值的预测总是偏低整体 MAPE 可能不高但峰值的偏差才是调度最在意的如果模型把峰值预测得偏高可能导致购电过量。画图是唯一能直观看到模型在哪段时间系统性偏差的方式。另外注意反归一化要在计算指标之前完成否则得到的 MAPE 是归一化空间上的数没有业务含义。5. 电力负荷时间序列预测避坑五个最常见的翻车点5.1 数据泄漏归一化 fit 了全部数据测试精度虚高现象训练 loss 和验证 loss 都很好MAPE 低到 1% 以下但模型部署到新数据上预测一塌糊涂。原因MinMaxScaler().fit(df[load])在整个数据集上执行了min和max在训练阶段就偷看了测试区间和未来信息。更隐蔽的是做差分时用了全序列均值。解决严格按时间顺序划分出训练集、验证集、测试集scaler只 fit 训练集再transform三部分。检查你代码里fit和split的先后顺序即可。5.2 预测因子不随时间错位测试集里的特征用了未来温度现象加入了温度特征后训练集收敛很快但实际应用时 MAPE 飙升。原因测试阶段使用的温度是「预报温度」训练阶段却用了「实测温度」。实测温度本身就是事后填充测试时拿不到同质量的输入。解决训练时就用历史气象预报数据或者在推理时对温度特征做扰动测试——把温度加减 2 度看预测结果变化是否合理。如果模型对温度极其敏感要警惕它把温度当成了主变量而真正核心的负荷历史反而被忽略了。5.3 滑窗步长过小导致样本高度重叠验证集失真现象训练集和验证集误差曲线几乎一模一样模型像「记住了」数据。原因step1产生的相邻样本只差一个时间点验证集中大量样本和训练集样本高度重叠模型其实在背题。时间序列里「相似样本」已经是数据泄漏的一种形式。解决把step设为predict_steps的整数倍比如predict_steps24时step24或step48保证验证集和训练集的样本区间没有大面积交叠。如果数据量有限至少保证测试集完全在时间轴上排在训练集之后。5.4 训练不设随机种子同一份数据每次跑出不同结果现象同一个代码、同一份数据每次训练完的误差忽高忽低用户以为代码不稳定。原因PyTorch 或 TensorFlow 初始化权重时用了随机数GPU 上的某些算子本身也有随机性。解决在训练脚本开头固定所有随机源。import random import numpy as np import torch def seed_everything(seed42): random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) seed_everything(42)固定随机种子后模型可复现是工程落地的底线。否则你做参数对比实验时分不清效果提升来自参数还是来自那次运气好的随机初始化。5.5 预测多步时误差累积24 步后曲线变成直线现象多步预测的结果在 10 步以后基本变成一条水平的直线或者振幅明显衰减。原因递归多步预测把第一步的预测值当作第二步的输入误差后续误差逐级累积模型倾向于输出均值以避免极端损失这是深度学习时序多步预测的通病。解决改用直接多步预测一次性同时输出 24 个点或者用 seq2seq 结构。本文的LoadForecastLSTM输出 24 个值就是直接多步请优先使用这种方案。如果源码里是循环代入的递归预测改输出层为多输出这是处理误差累积最直接的解。6. 进阶三种多步预测出口与模型验证习惯多步预测在电力负荷场景里不只是把模型输出维度改大那么简单它决定了模型结构和训练目标。第一种是递归多步把预测值作为输入回填进窗口代码写起来简单但误差会累积第二种是直接多步一次性输出未来 24 个点本文示例模型就是这样训练简单且不会累积误差缺点是模型内部没有显式建模步与步之间的相关性第三种是 seq2seq 结构编码器读历史窗口解码器逐步生成未来序列并用真实值或预测值训练表达能力最强但训练复杂度高。我建议普通工程先选直接多步业务上要更精细的曲线形态时再上 seq2seq。验证习惯比模型结构更重要。我每次训练完会做三件事第一把反归一化后的预测曲线和真实曲线画在同一坐标轴上重点看峰值时段和拐点时刻第二按星期几拆分误差如果周末的 MAPE 明显高于工作日说明周周期特征没学好需要补充is_weekend特征第三做一次平移测试——用最近一个月数据重新训练看指标是否稳定如果不稳定说明数据分布漂移严重模型需要定期重训而不是一次部署永久使用。这些验证习惯看似朴素却能挡住大多数「训练分数好看、上线就翻车」的情况。做时间序列预测最大的教训是模型永远不可能知道未来有没有突发事件它只是在已有模式上做条件外推。所以永远保留人工复核环节并且对模型的峰值预测打一个偏保守的折扣。把这份源码当成一个可靠的工具箱而不是一个黑匣子希望帮到你。本文还有配套的精品资源点击获取