
简介面向区域电力负荷预测与深度学习应用开发者的完整项目源码覆盖数据读取、特征工程、模型训练与评估等核心流程基于 Python 实现并可本地编译运行项目结构清晰适合毕业设计、课程实践或入门深度学习时序预测任务。包内共 62 个文件以 39 个 py 源码文件为主另配有可视化结果 jpg/png 图片、说明文档 md、编译缓存 pyc 及配置文件整体压缩包约 3.71MB轻量易部署。目前已有 133 人学习下载具备一定参考价值。模块设计上除模型主体外还提供数据处理模块、helper 工具函数、test 测试用例、trainer 训练封装以及 Notes 笔记和运行效果截图便于读者对照理解数据预处理、模型搭建、训练评估与结果可视化全流程代码分层清晰适合在此基础上扩展算法或迁移至更广泛的电力负荷预测场景。1. 从调度的痛点到深度学习负荷预测区域电力负荷预测并不只是学校课程或者论文里的一个课题它直接对应电网调度、发电计划、交易申报和需求响应这些生产环节。短期的负荷预测如果误差偏大火电就要多备旋转备用储能充放电策略也会跟着错位成本全是真金白银。传统的时间序列方法在节假日、极端天气和突发事件面前疲态尽显而深度学习模型能自动从历史负荷里挖出周期性和突变特征把预测精度推上一个新台阶。这个标题里的“完整源码说明”实际上是一个最小可行项目的打包形态数据准备、模型训练、评估验证、文档说明都在里面。对正在做电力数据分析的工程师或者想用深度学习入门时序预测的Python开发来说照着这个结构复现一遍能少踩很多无形的坑。接下来我会按数据、模型、训练、评估这条主干线把每个环节的代码和参数掰开讲。2. 电力负荷预测前的数据清洗与滑窗构造2.1 电力负荷序列的特征与常见脏数据电力负荷数据的最大特点是强周期性和强波动性。一般区域负荷有“日双峰”上午和晚上各一个峰值、周末比工作日低、夏季和冬季负荷高这种固定规律同时还叠加了温度、风力、光照和工商业生产安排带来的随机波动。数据粒度常见的有15分钟、30分钟、1小时采集到的时间序列往往带着缺失、零值、毛刺以及时间戳错位问题。拿到原始数据后我不会直接建模而是先做三件事一是检查时间戳是否连续缺了哪些时间点按业务规律用前后均值插值二是过滤明显不合理的负荷值比如某时刻负荷突然变成0或者超过变压器容量的几倍这类点通常是采集设备故障造成的三是确认数据是否来自同一统计口径尤其要注意负荷单位是MW还是kW混用会让模型的误差指标完全失真。数据质量检查的产出是一份连续、干净的序列这个步骤没做好后面深度学习模型再复杂也白搭。2.2 Python实现滑窗变监督样本深度学习模型读到的是二维矩阵而电力负荷本质是一维时间序列。要把时间序列变成输入输出对常见做法是滑窗用过去seq_len个时间点的负荷预测未来pred_len个时间点的负荷。滑窗构造监督样本的核心代码用NumPy就能写得非常简洁。import numpy as np def create_sequences(data, seq_len24, pred_len1): 将一维负荷序列转换为监督学习样本 :param data: 一维负荷数组shape(N,) :param seq_len: 输入窗口长度历史时间步数 :param pred_len: 预测长度未来时间步数 :return: X shape(样本数, seq_len), y shape(样本数, pred_len) X, y [], [] for i in range(len(data) - seq_len - pred_len 1): X.append(data[i:i seq_len]) y.append(data[i seq_len:i seq_len pred_len]) return np.array(X), np.array(y)这段代码的逻辑很直接从序列开头滑动遍历每个位置截取seq_len个历史值作为输入紧接着的pred_len个值作为标签。返回的X和y形状分别是(样本数, seq_len)和(样本数, pred_len)。后续喂给LSTM或TCN时还需要把X再扩展一个特征维度变成(样本数, seq_len, 特征数)。滑窗长度的选择要结合预测场景。预测未来15分钟到1小时的短临负荷seq_len取24或48即可预测未来多步或更长时间窗口往往需要拉到168一周才能让模型捕捉到日周期和周周期。窗口太短抓不住周期太长则样本量减少、训练成本上升我一般会先做一次滑动窗口敏感性实验再定具体值。2.3 归一化与时间特征编码电力负荷的值域波动大同一模型下不同区域的负荷可能从几十MW到上万MW不等直接喂给深度学习模型会导致梯度震荡、收敛缓慢。常见的做法是用MinMaxScaler或StandardScaler把负荷缩放到[0,1]区间。注意一个关键细节归一化参数只能从训练集上fit再应用到验证集和测试集不能在整个数据集上一次性fit否则会把未来的数据分布泄露给训练过程。from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler() # train_data 是训练区间的一维负荷序列 train_scaled scaler.fit_transform(train_data.reshape(-1, 1)).flatten() test_scaled scaler.transform(test_data.reshape(-1, 1)).flatten()除了负荷本身时间特征也很重要。小时、星期、节假日这类信息能帮助模型区分工作日峰值和休息日低谷。构造方法很简单把时间戳拆出hour、weekday、is_holiday三个字段再分别做归一化或one-hot编码。把连续的时间步看成周而复始的循环变量时也可以把小时数转为sin(2*pi*hour/24)和cos(2*pi*hour/24)两个值避免0点和23点在数值上距离过远。这里的时间特征会横向拼接到滑窗生成的特征矩阵的末尾形成最终的模型输入。3. 深度学习模型选型LSTM、TCN与Transformer3.1 为什么时序模型比MLP更靠谱如果只把过去24小时负荷拼接成一维向量丢进全连接网络模型会把它当成普通的静态特征完全丢失时间顺序上的依赖关系。电力负荷的核心是“今天这个小时的负荷和昨天同一小时、上一小时都有强关联”这种关联只能通过带时序结构的网络建模。在区域电力负荷预测里最常用的三类深度学习结构是LSTM、TCN和Transformer。LSTM通过门控机制解决长序列中的梯度消失问题能记住一周前的负荷模式TCN使用膨胀因果卷积在不递归的情况下覆盖更长的感受野训练并行度比LSTM高Transformer依靠自注意力机制直接建模任意两个时间步的关系对突变和长周期特征敏感。实际落地时如果数据量不大LSTM是稳妥的起点数据量几十万条以上且资源充足Transformer效果通常更好。从源码完整性的角度我倾向于先提供一个LSTM基线再预留换主干模型的接口。3.2 一个基于PyTorch的LSTM预测模型代码下面是一个可以直接运行的LSTM负荷预测模型类输入形状为(batch_size, seq_len, input_dim)输出为(batch_size, pred_len)。import torch import torch.nn as nn class LoadLSTM(nn.Module): def __init__(self, input_dim, hidden_dim64, num_layers2, pred_len1, dropout0.2): super().__init__() self.lstm nn.LSTM(input_dim, hidden_dim, num_layers, batch_firstTrue, dropoutdropout) self.fc nn.Linear(hidden_dim, pred_len) def forward(self, x): # x: (batch, seq_len, input_dim) out, (h_n, _) self.lstm(x) # out: (batch, seq_len, hidden_dim) last_h h_n[-1] # 取最后一层最后一个时间步的隐藏状态 return self.fc(last_h) # (batch, pred_len)代码里两个关键点batch_firstTrue让我们可以直接把形状为(样本数, seq_len, 特征数)的数据送进模型不用做维度置换h_n[-1]取的是最后一层LSTM在所有时间步处理完后的隐藏状态这个向量浓缩了整个输入窗口的信息再通过全连接层映射到pred_len个输出。注意dropout只在num_layers1时生效它随机丢弃部分神经元输出降低过拟合风险。如果输入里既包含标准化的负荷也包含时间特征那么input_dim 负荷特征数 时间特征数。在构造x时要把负荷序列和时间特征在最后一维拼接起来而不是把时间特征当作额外的样本。3.3 损失函数与优化器怎么选短期负荷预测本质是回归任务最常用的损失函数是均方误差MSE和平均绝对误差MAE。MSE对大误差的惩罚更重会让模型更努力去贴合峰值MAE对异常值更稳健但训练时梯度更新相对平稳。实际使用中可以先以MSE或MAE作为训练目标最后再用第五章里的三种指标统一评估。优化器首选Adam它对学习率的敏感度比SGD低基本不需要手动调整动量项。核心参数是学习率lr和weight_decay。区域电力负荷数据噪声不小我会给Adam加上一个很小的权重衰减1e-5到1e-4起正则化作用。此外如果训练过程中发现验证集损失平稳但测试集误差大说明模型过拟合应当减少LSTM层数或调大dropout而不是无脑增加模型容量。4. 训练、调参与排错让模型真正收敛4.1 按时间顺序切分数据集电力负荷数据是严格的时间序列随机切分训练集和测试集是致命的错误。未来的数据一旦混入训练集模型相当于提前看到了“答案”测试误差会虚低但真实部署时完全达不到同样性能。正确做法是把完整序列按时间顺序切成三段前60%-70%作为训练集接着的15%-20%作为验证集最后15%-20%作为测试集并且严格保证切分点不跨越任何样本构造窗口。滑窗构造样本时还需要注意同一时间点生成的训练样本之间存在重叠。比如seq_len24时样本0和样本1重叠了23个时间步这种重叠会让相邻训练样本高度相关导致验证集的效果比理论值略好。为了在调参时得到更诚实的结果可以把验证集样本之间的间隔拉大到seq_len或者在验证集上连续预测而不是逐点预测。python train.py \ --data data/load.csv \ --seq_len 72 \ --pred_len 1 \ --epochs 100 \ --batch_size 64 \ --lr 0.001 \ --early_stop 10 \ --save_model checkpoints/best.pt这是一条典型的模型训练启动命令。--seq_len定义了历史窗口--lr是初始学习率--early_stop表示验证集损失连续10个epoch不下降就停止训练。命令行参数化的好处是调参时不用改代码一个参数一个值地跑实验便于以后对照记录。4.2 关键超参的参考范围与调整顺序超参数参考范围调整优先级说明seq_len24 / 48 / 72 / 168高决定历史窗口需结合数据粒度和预测周期hidden_dim32 / 64 / 128高LSTM隐藏层维度影响网络容量num_layers1 / 2 / 3中层数增加能学更复杂映射但过拟合风险上升dropout0.1 / 0.2 / 0.3中只在多隐层时有效batch_size32 / 64 / 128低受显存影响影响训练稳定性lr0.001 / 0.0005 / 0.0001高学习率过大易发散过小收敛慢pred_len1 / 24 / 48高预测步数多步预测策略需另外设计我调参时不会一次性把所有参数都试一遍而是先固定一组较保守的配置seq_len48hidden_dim64num_layers2lr0.001。然后按“学习率 - 窗口长度 - 网络容量 - 正则化”的顺序逐步调。学习率先用手动或lr_scheduler扫一遍确认损失能稳定下降再放开其他参数。调seq_len时观察训练曲线的收敛速度如果模型在验证集上表现平稳再逐步加深网络。4.3 早停、学习率衰减与NaN排查训练循环里早停是性价比最高的正则化手段。验证集损失在若干epoch内不下降时就停止训练并载入验证集表现最好的模型权重。代码实现时用torch.save保存最优模型等训练结束后再torch.load恢复。学习率衰减和早停是配套的常见做法是用ReduceLROnPlateau当验证集损失停滞时把学习率降低为原来的0.1倍给模型一个更精细的下降步长。import torch from torch.optim.lr_scheduler import ReduceLROnPlateau optimizer torch.optim.Adam(model.parameters(), lr0.001) scheduler ReduceLROnPlateau(optimizer, modemin, factor0.1, patience5) best_val_loss float(inf) best_state None for epoch in range(epochs): train_one_epoch(model, train_loader, optimizer) val_loss validate(model, val_loader) if val_loss best_val_loss: best_val_loss val_loss best_state {k: v.cpu().clone() for k, v in model.state_dict().items()} scheduler.step(val_loss)这段代码里的train_one_epoch和validate是省略的训练/验证函数它们分别负责前向传播、损失计算和反向传播。注意best_state存的是权重张量的克隆防止后续模型参数继续更新时原始最优权重被覆盖。排错时看到loss变成nan优先检查输入数据有没有inf或极端的0值其次把学习率降到0.0001试一次如果还nan就检查LSTM里是否有数值不稳定操作。5. 评估指标与验证曲线预测值如何才算准5.1 回归误差指标选谁模型训练完不能只看训练损失我一般会同时看三个指标平均绝对误差MAE、均方根误差RMSE和平均绝对百分比误差MAPE。MAE用负荷同单位表示便于业务理解RMSE对大的偏差更敏感能够暴露某些极端点的预测失败MAPE则用于横向对比不同量纲的数据集。电力负荷本身带有很强的日周期如果MAPE在5%以内说明预测的峰谷趋势基本正确超过10%就要回去查数据和模型结构。5.2 逆归一化后计算指标模型输出的是归一化后的结果直接和原始负荷值相减没有任何意义。必须先把预测值和真实值统一通过scaler.inverse_transform还原成MW单位再计算误差指标。这一步放错位置是很多源码包的隐藏bug。from sklearn.metrics import mean_absolute_error, mean_squared_error # pred_scaled 和 y_scaled 分别是归一化的预测和真实值 pred scaler.inverse_transform(pred_scaled.reshape(-1, 1)).flatten() y_true scaler.inverse_transform(y_scaled.reshape(-1, 1)).flatten() mae mean_absolute_error(y_true, pred) rmse mean_squared_error(y_true, pred, squaredFalse) mape np.mean(np.abs((y_true - pred) / y_true)) * 100 print(fMAE: {mae:.2f} MW, RMSE: {rmse:.2f} MW, MAPE: {mape:.2f}%)这里的mean_squared_error在sklearn新版本里用squaredFalse返回RMSE老版本则用np.sqrt(mse)。注意MAPE的分母是真实负荷如果序列里存在接近0的低谷MAPE会异常放大这时候可以只统计白天9点到21点的样本或者改用对称平均绝对百分比误差SMAPE。5.3 画预测曲线定位峰谷误差误差指标只能给出一个数字真正要找问题还得靠可视化。我会把连续24小时的预测曲线与真实曲线画在一起再画一张误差直方图。如果预测曲线在峰值时刻整体偏低说明模型对峰值信息不敏感需要增加最近几小时负荷变化率的特征如果误差在凌晨负荷低谷段集中爆发说明模型把低谷数据也当成次要特征了可以尝试对低谷时段单独加权损失。import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.plot(y_true[:96], labelTrue Load, linewidth2) plt.plot(pred[:96], labelPredicted Load, linewidth2, linestyle--) plt.title(Load Prediction: Next 24 Hours) plt.xlabel(Time Step) plt.ylabel(Load (MW)) plt.legend() plt.tight_layout() plt.savefig(prediction_curve.png, dpi150)这条曲线不是给别人汇报用的也不仅仅是为了好看而是排查模型系统性偏差的最直接手段。当预测曲线和真实曲线在峰谷处贴合度明显差于平段时优先调整数据特征而不是模型结构当所有时段都出现整体偏移时先检查反归一化是否用了正确的scaler参数。验证的意义就在这里指标告诉你结果曲线告诉你下一步往哪改。本文还有配套的精品资源点击获取