
简介面向短期电力负荷预测场景的完整Python工程基于长短期记忆网络LSTM并由PyTorch实现适合电力数据分析学习者、深度学习入门者及需要落地负荷预测模型的开发者。资源整合了从数据预处理、模型搭建与训练到结果分析的全流程代码核心Notebook中利用Pandas解析Excel历史负荷数据并结合chinese_calendar获取节假日信息作为外部特征帮助模型更好地捕捉用电规律数据集中包含历史负荷与天气等多种字段支持按滑动窗口构造时序样本进而学习峰谷变化模式。同时提供训练好的模型权重可直接对指定日期的电力负荷曲线进行预测也可基于Notebook调整超参数或结构完成二次实验。包内共15个文件以Jupyter Notebook、Python脚本、xls数据集和结果图片为主附带最终模型文件与说明文档压缩包约5.46MB目录结构清晰图片直观呈现训练损失、真实与预测对比等分析图表。目前已有325人学习下载适合希望获得可运行、可复现的LSTM电力预测端到端参考方案的读者。1. 短期电力负荷预测为什么首选 LSTM电力负荷预测直接决定发电计划和售电偏差考核按时间尺度分成超短期分钟级、短期未来 17 天、中长期月度以上。短期预测最常用的输入是历史负荷、温度、湿度、星期类型输出是未来 24 小时的逐时负荷。传统 ARIMA 对非线性、节假日突变和多变量依赖处理起来很吃力而 LSTM 通过门控结构保留长期依赖在时序回归任务上往往比 XGBoost 更稳尤其是当历史序列存在明显日周期和周周期时。这个项目标题里提到的“Python 完整源码和数据”本质上就是一个可复现的端到端回归任务数据清洗、序列构造、模型训练、反归一化、误差评估。适合刚接触 LSTM 时间序列预测的工程师也适合需要把预测结果接入调度系统但不想从零推导公式的从业者。下面按我自己搭建这套预测方案的顺序展开从数据预处理到最终评估每一步都给出能直接跑的代码和参数依据。2. 电力负荷数据的清洗与序列化的三个关键点先明确数据形态负荷数据通常以 CSV 保存字段至少包含时间和 load 两列部分数据集带温度、湿度、是否工作日。拿到原始数据后不要急着训练第一步是检查时间索引是否连续、有没有缺失值、有没有明显的跳变。常见做法是把时间列解析成 datetime 并设为索引然后按固定频率重采样比如 15 分钟或 1 小时。短期预测如果用逐小时负荷一天就是 24 个点一周就是 168 个点这个数字决定了后面的时间步长选择。2.1 缺失值与异常值的处理策略负荷数据的缺失通常集中在凌晨或节假日处理方式不要一律填零或均值。零填充会直接把预测结果拉低均值填充会抹平真实波动。我一般先用线性插值补短缺失段超过 6 小时的连续缺失则用前后同星期同时间的负荷均值补。异常值用滑动窗口的 Z-score 检测窗口取 24 小时Z-score 超过 4 的点先标记出来再结合业务判断是真实用电事件还是采集故障。如果确认是坏数据用窗口内中位数替换。2.1.1 批量清洗代码与参数说明import pandas as pd import numpy as np df[time] pd.to_datetime(df[time]) df df.set_index(time).sort_index() # 重采样到1小时缺失值先留空 df df.resample(1h).mean() # 线性插值补短缺失连续缺口 6小时 df[load_interp] df[load].interpolate(limit6, limit_directionboth) # 超过6小时的缺失用历史同期均值补 missing df[load_interp].isna() for ts in df.index[missing]: same_weekday df.loc[(df.index.weekday ts.weekday()) ((df.index.hour ts.hour))][load] df.loc[ts, load_interp] same_weekday.median() # 滑动Z-score异常值检测 rolling_mean df[load_interp].rolling(24, centerTrue).mean() rolling_std df[load_interp].rolling(24, centerTrue).std() zscore (df[load_interp] - rolling_mean) / rolling_std df[load_fixed] df[load_interp].where(abs(zscore) 4, rolling_mean 2 * rolling_std)这段代码先重采样对齐时间频率再用 interpolate 的 limit 参数控制只补短缺口防止长缺口被线性插值硬拉成直线。历史同期均值补长缺失的思路是负荷具有强周期性同星期类型同小时的负荷均值比全局均值更有代表性。滑动 Z-score 的窗口选 24 是为了对齐日周期避免把每天的正常峰值误判成异常。2.2 多变量特征构造与星期特征编码单独用历史负荷训练 LSTM 也能出结果但加入温度会明显提升夏季和冬季预测准确率。如果数据集里没有温度可以用节假日标记和星期特征弥补。星期特征不要直接编码成 06 的整数这个数字大小关系会被模型误解成连续量。正确做法是 one-hot 编码如果是 7 种星期就生成 7 列。节假日建议单独一列0/1 标记因为节假日的负荷形态和工作日差很多。2.3 固定时间步长构造有监督样本LSTM 的输入形状是(样本数, 时间步长, 特征数)。时间步长选多少决定了模型记忆多长的历史。短期电力预测常用的三个选择24看一天、48看两天、168看一周。我一般先测 24 和 168 的对比如果数据量大且周期性强168 往往更好但训练时间会变成原来的 7 倍。构造样本时注意不能 shuffle否则时间顺序被打乱预测就失去意义。切分流程是先按时间顺序切训练集和测试集再分别构造样本顺序如下def create_sequences(data, feature_cols, target_col, lookback): X, y [], [] for i in range(lookback, len(data)): X.append(data.iloc[i - lookback:i][feature_cols].values) y.append(data.iloc[i][target_col]) return np.array(X), np.array(y) train_data df.iloc[:train_len] test_data df.iloc[train_len - lookback:] # 保留交叉部分 X_train, y_train create_sequences(train_data, feature_cols, load_fixed, lookback) X_test, y_test create_sequences(test_data, feature_cols, load_fixed, lookback)这里最关键的是测试集起始位置从train_len - lookback开始取保证测试集每一条样本都能看到训练集末尾的真实历史数据。如果直接按train_len起始测试集前 lookback 个时间点的样本就用到了测试集信息和真实预测场景不一致。3. LSTM 模型结构与 PyTorch 实现细节短期电力预测的 LSTM 不需要堆太深。常见配置是两层 LSTM 加一层全连接隐藏单元数量在 32 到 128 之间。输入特征数等于选好的特征列数输出维度是 1代表下一个小时的负荷值。训练时要把数据归一化到 01 或 -11 之间LSTM 内部的 tanh 激活函数对输入缩放很敏感不归一化直接训练会导致梯度爆炸或者收敛极慢。归一化参数只能从训练集统计测试集用同样的参数转换防止未来数据泄漏。3.1 LSTM 遗忘门对负荷预测的影响LSTM 的遗忘门决定上一时刻的隐藏状态有多少被保留。短期负荷预测里周周期特征跨越了 168 个时刻遗忘门需要学会在白天末端保留傍晚负荷趋势在夜晚末端丢掉白天的高频噪声。如果遗忘门偏置初始化为 1模型一开始倾向于记住全部历史训练后期再学习选择性遗忘这个初始化技巧在短序列上能加快收敛。PyTorch 默认遗忘门偏置是 0需要手动调整。3.2 完整模型定义和训练参数表下面给出一个可运行的 PyTorch 模型比 Keras 版本更容易控制训练细节也方便后期改成多步预测。import torch import torch.nn as nn class LSTMPredictor(nn.Module): def __init__(self, input_size, hidden_size, num_layers, output_size1): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue, dropout0.2 if num_layers 1 else 0) self.linear nn.Linear(hidden_size, output_size) def forward(self, x): # x: (batch, seq_len, input_size) out, _ self.lstm(x) # out: (batch, seq_len, hidden_size) out self.linear(out[:, -1, :]) # 取最后一个时间步 return out.squeeze(-1) model LSTMPredictor(input_sizelen(feature_cols), hidden_size64, num_layers2, output_size1)训练参数我会这样设损失函数用 HuberLoss 而不是 MSE因为负荷曲线偶尔有尖峰Huber 对尖峰的梯度比 MSE 温和能避免模型过度偏向少数异常样本。优化器选 Adam初始学习率 0.001如果 10 个 epoch 验证损失不下降就乘以 0.5。批量大小 64epoch 上限 100配合早停。参数推荐值说明lookback24 或 16824 看日周期168 看周周期hidden_size64负荷规律不复杂128 收益有限num_layers21 层欠拟合3 层易过拟合dropout0.2防止对重复节假日模式过拟合batch_size64与数据量相关数据少可减到 32optimizerAdam自适应学习率避免手动调衰减lossHuberLossdelta1.0 效果比较稳这个配置在多数公开电力负荷数据集上都能在 50 epoch 左右收敛。如果训练 loss 一直震荡先检查学习率是否太大再检查归一化是否误把测试集统计量混了进去。3.3 训练循环中的梯度裁剪与学习率调度LSTM 训练最常见的坑是梯度爆炸尤其在序列长度 168 时。在每次 backward 之后、step 之前加clip_grad_norm_(model.parameters(), 1.0)这样即使某个 batch 出现极端值也不会让权重跳到坏区域。学习率调度用 ReduceLROnPlateau监控验证集 HuberLosspatience 设为 5。训练时把训练集再切出最后 7 天做验证集模拟真实预测场景。optimizer torch.optim.Adam(model.parameters(), lr0.001) scheduler torch.optim.lr_scheduler.ReduceLROnPlateau( optimizer, modemin, factor0.5, patience5) criterion nn.HuberLoss(delta1.0) for epoch in range(100): model.train() for X_batch, y_batch in train_loader: optimizer.zero_grad() pred model(X_batch) loss criterion(pred, y_batch) loss.backward() torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0) optimizer.step() model.eval() with torch.no_grad(): val_pred model(X_val) val_loss criterion(val_pred, y_val) scheduler.step(val_loss) if early_stop_counter 10: break这里 train_loader 和 X_val 需要在训练前用 DataLoader 封装注意训练时 shuffleTrue 可以加快收敛但验证集和测试集必须 shuffleFalse。每个 epoch 结束后计算验证损失并传给 schedulerscheduler 会判断是否降低学习率。4. 基于 PyTorch 数据集的完整训练与评估流程代码和模型结构都有了接下来要把它组织成可复现的工程流程。标题里强调“完整源码和数据”那么工程上应该包含数据读取模块、预处理模块、模型模块、训练模块、评估模块。下面这套流程我用在多个项目里重点在于评估指标和反归一化步骤这是很多人忽略的地方。4.1 将序列数据封装成 PyTorch Dataset直接把 numpy 数组送给 DataLoader 也能训练但封装成 Dataset 类可以统一处理归一化和特征变换后期换数据集时不用改训练循环。下面给出一个简单的 Dataset 实现其中归一化器在外部传入保证训练和测试使用同一套统计值。from torch.utils.data import Dataset, DataLoader class LoadDataset(Dataset): def __init__(self, X, y): self.X torch.tensor(X, dtypetorch.float32) self.y torch.tensor(y, dtypetorch.float32) def __len__(self): return len(self.X) def __getitem__(self, idx): return self.X[idx], self.y[idx] train_dataset LoadDataset(X_train, y_train.astype(np.float32)) test_dataset LoadDataset(X_test, y_test.astype(np.float32)) train_loader DataLoader(train_dataset, batch_size64, shuffleTrue) test_loader DataLoader(test_dataset, batch_size256, shuffleFalse)注意 y_train 从归一化后的目标列取出后训练的是标准化区间的数值。最终评估时要把预测结果反归一化回实际负荷再计算误差指标。如果不反归一化RMSE 数值完全没有业务含义。4.2 多步预测演示递归预测未来 24 小时刚才定义的模型一次只预测下一个小时。如果要预测未来 24 小时常见做法有两个一是直接修改模型输出维度为 24但这样要求每个样本的标签是未来 24 小时的向量训练数据构造方式不同二是递归预测把当前预测值作为下一次输入循环 24 次。递归预测误差会累积但在短期范围内通常可接受。下面给出递归预测代码model.eval() predictions [] current_seq X_test[0] # (lookback, input_size) with torch.no_grad(): for _ in range(24): x_tensor torch.tensor(current_seq, dtypetorch.float32).unsqueeze(0) pred model(x_tensor).item() predictions.append(pred) # 用预测值替换序列末端的负荷特征 next_seq np.copy(current_seq) next_seq[:-1] current_seq[1:] next_seq[-1, feature_cols.index(load_fixed)] pred current_seq next_seq这段代码的关键在于更新当前序列时只替换负荷特征列其他特征如温度、星期需要同步更新否则序列会错位。如果只需要评估模型本身的单步误差直接用测试集逐点预测更可靠递归预测适合真正要对外输出预测曲线的场景。4.3 误差指标与反归一化评估单步预测评估时预测结果是归一化区间内的数需要先反归一化再与真实负荷对比。反归一化就是把每个数乘以训练集的 feature_std 再加上 feature_mean。评估指标一般看三个MAE、RMSE、MAPE。电力行业最关心 MAPE因为能直观反映偏差百分比。# scaler 是训练时用 StandardScaler 对特征列的拟合对象 pred_load scaler.inverse_transform( np.concatenate([pred_array.reshape(-1, 1), np.zeros((len(pred_array), num_feat - 1))], axis1) )[:, 0] true_load scaler.inverse_transform( np.concatenate([y_test.reshape(-1, 1), np.zeros((len(y_test), num_feat - 1))], axis1) )[:, 0] mae np.mean(np.abs(pred_load - true_load)) rmse np.sqrt(np.mean((pred_load - true_load) ** 2)) mape np.mean(np.abs((pred_load - true_load) / true_load)) * 100上面的技巧是统一用 scaler.inverse_transform 处理整行特征目标列取第一列其他列补零。这样避免对单个值单独写反归一化函数。如果数据里有多个特征也可以用同样方法还原全部特征列再取目标列。5. 从模型训练到短期预测落地的四个调试技巧模型跑通只是第一步真正要部署到业务里还需要处理一些边界问题。最后分享几个我调试电力预测模型时最常用的技巧这些经验比调参本身更值钱。5.1 用残差图识别节假日预测偏差预测结束后把误差按时间画散点图。如果发现误差在法定节假日前后出现大尖峰说明模型没有学到节假日特征或者节假日样本太少。简单补救方法是把节假日单独做一列 0/1 标记同时把节假日前一天也标记为 0.5 或单独一列让模型感知节前负荷转移。5.2 模型融合LSTM 加 XGBoost 残差修正LSTM 预测值做基础然后用 XGBoost 对残差建模。把 LSTM 预测值、星期、小时、温度作为特征目标是真实负荷减 LSTM 预测值。XGBoost 对非线性残差的拟合能力很强能修正节假日或极端天气情况。这个小技巧不需要改原模型只增加了一个轻量级的修正环节。5.3 检查数据泄漏的一个小实验把训练集中时间靠后的样本故意屏蔽掉重新训练模型如果测试集误差变化巨大说明之前存在数据泄漏。常见的泄漏点有两个归一化时使用了全部数据的均值和标准差构造序列时在训练集和测试集边界有重叠但没有清理。检查方法很简单打印训练集和测试集的时间范围确认测试集起始时间严格晚于训练集。5.4 预测结果平滑的后处理LSTM 对单点预测会出现毛刺尤其是跨天交接处。可以用简单的指数平滑对输出曲线做后处理公式是y_t α * y_pred (1 - α) * y_{t-1}α 取 0.7。注意这个平滑只影响展示或上报不影响模型训练。如果业务要求足够精确平滑可能会增大 MAPE所以先用真实评估结果验证再决定是否启用。最后记得把所有源码按模块组织好数据文件单独存放训练前打印数据时间范围、样本数量、特征列表。加载时间序列模型时重新构造相同 lookback 长度的输入序列并沿用训练时保存的 scaler 参数这是线上与离线结果一致的关键。本文还有配套的精品资源点击获取