简介这份PDF论文面向电力系统调度、电力市场交易及新能源并网领域的研究人员与工程技术人员聚焦短期电力负荷预测这一关键问题。针对传统统计学方法对负荷平稳性要求高、普通机器学习难以兼顾负荷时序依赖与多因素非线性影响的局限论文提出基于长短期记忆单元LSTM构建深度循环神经网络的预测方法可灵活定义历史窗口期、灵活添加负荷影响因素并借助遗忘门、输入门、输出门三个门控单元实现对长距离时序依赖的建模。资源包共1个PDF文件大小约1.45MB内容涵盖RNN与LSTM结构原理、负荷预测模型基本思路、不同历史时间窗口与网络架构的性能验证及与其他算法的对比实验。目前已有479人学习适合希望掌握深度学习时序建模方法、提升负荷预测准确性与稳定性的读者参考可从中获取完整的建模思路、实验设计与算法对比分析。1. 短期电力负荷预测为什么总在晚高峰翻车LSTM 能补上哪块短板做过电网侧负荷预测的同行大多有过类似经历白天曲线拟合得漂漂亮亮一到 18 点到 21 点的晚高峰预测值就明显偏低第二天调度计划被迫临时调整。问题往往不在模型不够深而在于传统方法把负荷序列当成若干独立点的组合忽略了「前一小时的状态会持续影响后一小时」这种时间依赖。短期电力负荷预测要解决的正是未来 1 小时到 1 天这个尺度上如何用历史负荷、温度、星期属性等输入把下一段曲线尽量贴近真实值。LSTM长短期记忆网络作为循环神经网络的一种改进结构靠输入门、遗忘门、输出门三个机制把「该记多久、该忘什么」变成可学习参数天然适合处理这种带周期性和突变性的时间序列。这篇笔记面向已经会写 Python、想把这套方案真正跑起来的人从数据构造、模型搭建、训练调参到上线前验证一步步拆开讲顺带把那些让我返工好几次的坑标出来。2. 从原始负荷表到 LSTM 可吃的张量数据管道怎么搭2.1 先想清楚 LSTM 到底在学什么LSTM 单元在每个时间步接收两个东西当前时刻的输入向量 x_t以及上一时刻传下来的隐藏状态 h_{t-1} 和细胞状态 C_{t-1}。它内部做四件事——遗忘门决定 C_{t-1} 里哪些信息丢掉输入门决定当前输入里哪些写进细胞状态然后更新细胞状态输出门决定这一步对外吐出什么隐藏状态。放到负荷预测场景里这意味着模型不是孤立地看「今天 19 点多少度、星期几」而是会结合「过去 24 小时负荷怎么爬升、昨天同一时段什么水平」来推断。这也是它比单纯的全连接网络或 ARIMA 更适合短期负荷的原因ARIMA 对线性趋势和固定周期还行遇到气温骤降导致的负荷跳变就容易失准而 LSTM 的门控结构对非线性突变更宽容。选型上还有几个现实考量。如果只做单步预测预测下一小时单层 LSTM 加一个全连接输出层通常够用如果要做未来 24 小时的多步预测要么用 Seq2Seq 结构要么把输出维度直接设成 24让模型一次性吐出整段曲线。我一般倾向后者因为实现简单、训练稳定代价是输出之间缺少显式依赖约束后面可以用平滑后处理补。2.2 数据清洗与特征工程的具体做法拿到手的负荷数据通常是 15 分钟或 1 小时粒度的 CSV列里可能有时间戳、有功负荷、温度、湿度、节假日标记。第一步不是急着喂模型而是处理三类脏数据缺失值、异常值、时间对齐。缺失值常见于采集设备掉线连续缺几个点可以用线性插值缺一大段比如超过 6 小时建议直接标记为无效样本别硬填。异常值用滑动窗口的 3σ 或 IQR 判断负荷突然从 800MW 跳到 2000MW 又跳回来基本是采集故障按前后均值修正。特征方面除了原始负荷我一般会构造这几类小时、星期、是否节假日这类时间特征做 one-hot 或 sin/cos 周期编码温度、体感温度直接归一化过去 24 小时和过去 7 天同一时刻的负荷作为滞后特征。注意滞后特征在训练集和测试集之间不能穿越否则会引入未来信息。import pandas as pd import numpy as np def build_features(df, load_colload, temp_coltemp): df df.copy() df[hour] df.index.hour df[weekday] df.index.weekday # 周期编码避免 23 点和 0 点被当成距离很远 df[hour_sin] np.sin(2 * np.pi * df[hour] / 24) df[hour_cos] np.cos(2 * np.pi * df[hour] / 24) df[weekday_sin] np.sin(2 * np.pi * df[weekday] / 7) df[weekday_cos] np.cos(2 * np.pi * df[weekday] / 7) # 滞后特征过去 24 小时、过去 7 天同一时刻 df[lag_24] df[load_col].shift(24) df[lag_168] df[load_col].shift(168) # 滑动统计 df[roll_mean_24] df[load_col].rolling(24).mean() df[roll_std_24] df[load_col].rolling(24).std() df df.dropna() return df这段代码的关键点在于周期编码用 sin/cos 而不是直接给 0-23 的整数是因为整数会让模型误以为 23 点和 0 点相隔很远而实际上它们是相邻的。lag_24 和 lag_168 分别捕捉日周期和周周期roll_mean_24 给模型一个近期基线参考。dropna 会丢掉前 168 行这是构造滞后特征的必然代价数据量少的时候要权衡是否保留 lag_168。2.3 归一化与滑动窗口切样本负荷值动辄几百上千 MW直接喂网络会导致梯度爆炸必须归一化。我一般用 MinMax 缩放到 [0,1]注意 scaler 只能在训练集上 fit然后 transform 测试集否则就是数据泄漏。滑动窗口是把长序列切成 (输入长度, 特征数) 的样本。假设用过去 48 小时预测未来 1 小时窗口就是 48步长为 1。from sklearn.preprocessing import MinMaxScaler def make_windows(data, target_col_idx, window48, horizon1): X, y [], [] for i in range(len(data) - window - horizon 1): X.append(data[i:iwindow]) y.append(data[iwindow:iwindowhorizon, target_col_idx]) return np.array(X), np.array(y) scaler MinMaxScaler() train_scaled scaler.fit_transform(train_df.values) test_scaled scaler.transform(test_df.values) target_idx train_df.columns.get_loc(load) X_train, y_train make_windows(train_scaled, target_idx, window48, horizon1) X_test, y_test make_windows(test_scaled, target_idx, window48, horizon1)window48 表示回看两天horizon1 表示预测下一小时。如果做 24 小时预测把 horizon 改成 24y 的形状会变成 (样本数, 24)。这里有个容易忽略的点归一化是对所有列一起做的包括温度、滞后负荷所以 scaler 的维度要和特征数一致预测时反归一化只取负荷那一列。3. PyTorch 搭 LSTM 预测模型层数、隐藏维度和训练循环怎么定3.1 网络结构设计与参数含义PyTorch 的 nn.LSTM 几个核心参数input_size 是每个时间步的特征数hidden_size 是隐藏状态维度num_layers 是堆叠层数batch_firstTrue 让输入形状变成 (batch, seq, feature)符合直觉。输出有两个output 是每个时间步的隐藏状态h_n 和 c_n 是最后一步的做单步预测时通常取 output 的最后一个时间步。隐藏维度怎么定我试过 32、64、128、256在几千到几万条样本的量级上64 到 128 通常性价比最高。再大容易过拟合尤其数据只有一两年的时候。层数上单层够用两层能捕捉更复杂的时序模式但训练时间翻倍且需要更多数据支撑。dropout 加在层间0.1 到 0.3 之间。import torch import torch.nn as nn class LoadLSTM(nn.Module): def __init__(self, input_size, hidden_size64, num_layers1, output_size1, dropout0.1): super().__init__() self.hidden_size hidden_size self.num_layers num_layers self.lstm nn.LSTM( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, dropoutdropout if num_layers 1 else 0 ) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): # x: (batch, seq_len, input_size) out, (h_n, c_n) self.lstm(x) # 取最后一个时间步的输出 last out[:, -1, :] return self.fc(last)注意 dropout 只在 num_layers 1 时生效单层加 dropout 在 PyTorch 里会报警告。fc 层把 hidden_size 映射到 output_size单步预测就是 1多步就是 24。forward 里取 out[:, -1, :] 是标准做法因为最后一步的隐藏状态已经聚合了整个窗口的信息。3.2 训练循环与损失函数选择损失函数用 MSELoss 最常见但电力负荷里晚高峰的绝对误差往往比凌晨大如果业务更关心高峰段精度可以考虑对高峰样本加权或者用 MAE 降低对异常值的敏感度。优化器 Adam 起步学习率 1e-3配合 ReduceLROnPlateau 在验证损失不降时减半。from torch.utils.data import DataLoader, TensorDataset device torch.device(cuda if torch.cuda.is_available() else cpu) model LoadLSTM(input_sizeX_train.shape[2], hidden_size64, num_layers1).to(device) criterion nn.MSELoss() optimizer torch.optim.Adam(model.parameters(), lr1e-3) scheduler torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience5, factor0.5) train_loader DataLoader( TensorDataset(torch.FloatTensor(X_train), torch.FloatTensor(y_train)), batch_size64, shuffleTrue ) for epoch in range(100): model.train() total_loss 0 for xb, yb in train_loader: xb, yb xb.to(device), yb.to(device) optimizer.zero_grad() pred model(xb) loss criterion(pred, yb) loss.backward() # 梯度裁剪防止 LSTM 梯度爆炸 torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0) optimizer.step() total_loss loss.item() scheduler.step(total_loss)batch_size64 是常见起点样本少就降到 32。梯度裁剪 max_norm1.0 对 LSTM 几乎是必备的因为循环结构反向传播时梯度容易累积爆炸不加这个经常训练几个 epoch 后 loss 变 NaN。shuffleTrue 打乱样本顺序避免模型学到样本排列的伪规律。3.3 验证集划分与早停时间序列不能随机划分验证集否则未来信息会泄漏到训练里。正确做法是按时间顺序切前 70% 训练中间 15% 验证最后 15% 测试。早停策略是验证损失连续 10 个 epoch 不降就停保存验证损失最低的模型权重。best_val_loss float(inf) patience_counter 0 patience 10 for epoch in range(100): # ... 训练代码 ... model.eval() with torch.no_grad(): val_pred model(torch.FloatTensor(X_val).to(device)) val_loss criterion(val_pred, torch.FloatTensor(y_val).to(device)).item() if val_loss best_val_loss: best_val_loss val_loss torch.save(model.state_dict(), best_lstm.pth) patience_counter 0 else: patience_counter 1 if patience_counter patience: break这套流程跑下来在典型的地市级负荷数据上单步预测的 MAPE 通常能压到 2% 到 4%比 ARIMA 的 5% 到 8% 有明显改善。但别只看 MAPE晚高峰时段的误差单独统计一下那才是调度真正关心的。4. 预测结果不达标时先查这几处LSTM 负荷预测的避坑清单4.1 现象训练 loss 正常下降验证 loss 却一路飙升原因典型过拟合常见于数据量少但 hidden_size 开太大或者 num_layers 堆到 3 层以上。另一个隐蔽原因是特征里混入了未来信息比如归一化时用了全量数据的 min/max。解决先把 hidden_size 降到 32 或 64num_layers 回到 1加 dropout 0.2。然后检查 scaler 是否只在训练集 fit。如果还不行减少特征数量把相关性低的温度、湿度先去掉只留负荷滞后和时间特征。4.2 现象预测曲线整体滞后真实值一个到两个小时原因模型倾向于输出「上一时刻的值」作为预测尤其在负荷变化平缓时MSE 损失会奖励这种保守策略。窗口太长也会加剧这个问题因为模型被太多历史信息淹没。解决缩短输入窗口从 48 降到 24 试试。损失函数换成 MAE 或 Huber对偏差更敏感。还可以在特征里加入负荷的一阶差分让模型直接看到变化趋势。4.3 现象晚高峰预测值系统性偏低原因训练样本里高峰时段占比小模型没学够。另外温度特征如果只用了当前时刻模型无法感知「持续高温导致负荷累积」这种效应。解决对高峰时段样本加权比如 18 点到 21 点的样本 loss 乘以 2。温度特征加入过去 3 小时的滑动平均。如果数据里有节假日标记确保它被正确编码因为节假日高峰形态和工作日完全不同。4.4 现象多步预测时后面几步误差急剧放大原因直接多输出output_size24时各步之间没有依赖约束模型对远期预测趋于保守或发散。Seq2Seq 结构如果解码器训练不充分也会这样。解决改用滚动预测每次只预测一步把预测值填回输入窗口再预测下一步。代价是误差会累积但短期6 小时内通常比直接多输出稳。或者用 Seq2Seq 加 teacher forcing训练时按一定概率喂真实值。4.5 现象换一批新数据后模型完全失效原因负荷模式随季节、经济结构变化而漂移年初训练的模型到夏天可能就不准了。归一化参数如果固定不变新数据的分布偏移会让输入超出训练时的范围。解决建立定期重训机制比如每月用最近 12 个月数据重新训练。归一化参数用滚动窗口更新或者改用对分布偏移更鲁棒的标准化方法。上线后监控预测误差超过阈值就触发告警。5. 把 MAPE 再压一个点几个我反复验证过的调优技巧模型能跑通只是起点真正拉开差距的是细节。第一个技巧是残差建模先用 LSTM 预测一个基线然后把残差真实值减预测值拿出来看它是否还有规律。如果残差在特定时段呈现周期性说明模型漏掉了某个特征把它补进去往往能直接降 0.5 到 1 个百分点。我一般会画残差的 ACF 图如果滞后 24 小时还有显著相关就说明日周期没学干净。第二个技巧是多模型融合。LSTM 对突变敏感但对平稳段有时不如简单的持久性模型直接用昨天同一时刻的值。把 LSTM 输出和持久性模型的输出按验证集误差加权平均权重用逆误差法通常比单模型稳。具体做法是在验证集上分别算两个模型的 MAPE权重 w (1/MAPE_lstm) / (1/MAPE_lstm 1/MAPE_persist)然后加权求和。第三个技巧是输入窗口的精细选择。别默认用 24 或 48用验证集做网格搜索试 12、24、36、48、72看哪个窗口的验证 MAPE 最低。不同地区、不同季节的最优窗口可能不一样我见过夏季最优是 36、冬季最优是 24 的情况因为冬季负荷对近期温度更敏感。第四个技巧是学习率预热。LSTM 训练初期梯度不稳定前 5 个 epoch 用线性预热从 1e-5 升到 1e-3之后再正常衰减。这个改动让我的模型收敛更稳最终 MAPE 平均降了 0.3 个点。# 学习率预热示例 def warmup_lr(epoch, warmup_epochs5, base_lr1e-3): if epoch warmup_epochs: return base_lr * (epoch 1) / warmup_epochs return base_lr for epoch in range(100): lr warmup_lr(epoch) for param_group in optimizer.param_groups: param_group[lr] lr # ... 训练 ...验证方法上除了 MAPE我建议加一个高峰时段命中率指标预测值落在真实值 ±5% 范围内的样本占比单独统计 18 点到 21 点。这个指标比整体 MAPE 更能反映调度可用性。上线前用最近三个月的数据做滚动回测每周重训一次看指标是否稳定。最后说个血泪教训别在特征工程没做干净的时候就去调模型超参我曾经花了两天调 hidden_size 和层数最后发现是归一化时把测试集数据混进去 fit 了 scaler修掉之后模型直接好了。先保证数据管道正确再谈调优。希望帮到你。本文还有配套的精品资源点击获取