简介:电力日负荷曲线预测程序与配套数据集主要面向电力系统调度人员、能源数据分析师和机器学习初学者,用于解决未来一天电力负荷曲线的预测建模与可视化问题。压缩包共23个文件,约2.8MB,其中14个Python脚本构成程序主体,覆盖界面构建、数据处理和预测输出等环节;同时包含4个CSV数据文件、2个Excel表格、2份Word说明文档及1个txt环境依赖文件。数据内容涵盖2022年至2023年多个时间段的实测负荷记录、待测日数据以及天气负荷关联信息,便于用户按训练、验证和预测场景拆分使用。借助这一资源,学习者可以获得一套可实际运行的参考框架、多格式负荷数据样本与所需环境说明,较完整地走通历史数据清洗、特征组织、模型训练、曲线生成与结果展示等步骤,对于课程设计、毕业设计或电力负荷预测方向的入门实践都有直接帮助。目前已有676人学习下载,适合希望快速上手负荷曲线预测项目并二次扩展功能的人群。
1. 项目概述与核心价值
做电力数据分析的人,应该都躲不过负荷预测这道坎。无论是电网调度、售电公司交易策略,还是工厂内部用能管理,预判未来一天的负荷曲线都是刚需。我这次整理的这套电力日负荷曲线预测程序和配套数据集,核心任务就是输入历史负荷数据,输出未来24小时的逐点预测曲线,颗粒度可以做到15分钟、30分钟或1小时一采,具体看原始数据分辨率。
这套东西解决的典型问题包括:今天要报明天的用电计划,但手工估误差大;交易市场需要在日前报量,报高了报低了都要承担偏差费用;工厂需要结合负荷预测安排错峰生产。本质上,它就是一个时间序列预测问题,但因为负荷数据本身有强周期性、强随机性和多因素耦合的特点,做起来比普通序列预测要讲究得多。
适合谁参考?一类是电力专业的研究生和工程师,需要快速搭一套可复现的基线模型;另一类是刚接触时序预测的数据算法工程师,想要一份完整从数据处理到模型评估的参考代码。我会把整个方案的设计逻辑、数据集构造方式、算法选型思路、实际训练调参过程以及踩过的坑全部写清楚,代码和我用的数据集也可以直接延伸复用。
这套方案里我最终落地的是以LSTM为主、以XGBoost做对照、加上一套完整的特征工程和评估流程的框架。后面我会逐个环节拆开讲,包括为什么用这些方法、有哪些替代方案、实际训练的时候哪些参数是真正敏感的。
2. 整体设计与预测任务拆解
2.1 这个预测任务到底在预测什么
日负荷曲线预测说白了就是:给定截止到当前时刻的历史负荷观测序列,预测未来24小时内各时间断面的负荷值。假设我们按1小时间隔采样,那么一天就是24个预测点;如果按15分钟间隔,就是96个点。这区别于“预测明天的峰值负荷”或“预测明天的总用电量”,属于多步时序预测,而不是单点回归。
由于预测的是一个曲线而不仅是单个数值,评估结果时也不只看一个误差,而是要看整条曲线每个时间断面上的贴合程度。我自己的习惯是同时看三组指标:平均绝对百分比误差MAPE、均方根误差RMSE,以及峰值时段的误差。峰值误差单独拎出来是因为电力场景里,峰时预测偏差直接关系到容量准备和调度安排,哪怕全天平均误差很小,峰时差了10%在实际业务中也是不可接受的。
任务设计的另一个关键在于输入窗口的长度。用多长的历史序列来预测未来24小时,直接影响模型能学到什么。我实验下来,用前7天168个小时的负荷数据作为输入窗口效果比较稳。太短(比如只用前一天24小时)会导致模型难以捕捉周周期性和趋势;太长(比如30天)不仅训练耗时增加,而且对于负荷波动这类非平稳序列,过长的窗口可能引入噪音。
2.2 方案选型:为什么用LSTM而不是别的
时序预测可选的方案确实很多。传统统计模型有ARIMA、指数平滑、季节性分解;机器学习模型有XGBoost、LightGBM、随机森林;深度模型有LSTM、GRU、TCN、Transformer。这个项目里我为什么最终以LSTM为主线?
第一,负荷数据有明显的昼夜周期、工作日/周末差异、季节趋势,LSTM的门控机制在捕捉这种长距离依赖关系上表现得非常稳定。第二,LSTM可以天然处理变长序列输入,适合做多步预测的seq2seq结构——把历史序列编码成一个隐含状态,再解码出未来24个点。第三,相比Transformer,LSTM对数据量的要求低很多,电力负荷数据往往只有几万条甚至几千条样本,Transformer在这种规模下很容易欠拟合或过拟合,而LSTM在中小规模数据集上的表现更稳健。
当然,XGBoost这类树模型也可以做,而且如果特征工程做得足够强,XGBoost的效果甚至可能超过不加精细处理的LSTM。但它需要你手动构造滞后特征、滑动窗口统计特征、日历特征,工程量和特征设计难度都不低。LSTM的优势在于它可以自动从原始序列里学习特征表示,所以在数据较干净的前提下,LSTM的端到端特性让它更适合作为这个项目的核心方案。
我最后采用的做法是LSTM主模型 + XGBoost对照模型,用同一套数据集和评估脚本做对比。这样既能验证深度模型在小规模电力数据上的有效性,也能给读者一个直观的模型性能参照系。
2.3 数据集的构造逻辑
数据集质量直接决定预测效果,这一点怎么强调都不过分。我选的公开数据集是某区域电网真实采集的负荷记录,时间跨度覆盖一整年,包含日期、时刻、负荷值三个核心字段。为提高模型鲁棒性,我额外合并了当天的温度数据,因为温度与空调负荷之间有很强的相关性,对夏季和冬季的负荷峰值影响显著。
数据预处理是重中之重。原始数据里存在少量缺失值和明显的异常尖峰(比如采集设备瞬时故障导致的跳变)。我的处理策略是:缺失值用前后24小时同断面的均值填充,异常值通过3-sigma原则识别,识别出后用线性插值替换。这个逻辑模拟了真实业务里数据不干净的普遍情况,也是在给模型打基础。
处理后,我对数据集按7:1.5:1.5比例划分训练集、验证集和测试集。注意这里有个很多人容易犯的错:时间序列数据不能随机打乱划分,必须按时间顺序切分,否则会造成严重的数据泄露——模型见过“未来”的数据,验证结果虚高,上线就崩。
2.4 为什么不能直接拿原始负荷值丢给模型
对LSTM这类深度模型来说,输入数据的尺度敏感度很高。负荷值动辄几百上千兆瓦,而温度特征是30度左右,日期编码是0到6,三者量纲差异巨大。如果不做归一化,模型训练时梯度更新会被大数值特征主导,收敛很慢且效果差。
我这里用的是MinMax归一化,把每个特征压缩到[0, 1]区间。这么做有几个好处:一是保持特征的相对关系不变,二是适合LSTM的激活函数(tanh/sigmoid)工作区间,三是对异常值有一定的容忍度。归一化要在训练集上计算最大最小值,然后用同样的参数应用到验证集和测试集,这个顺序不能乱。
简单的说,如果你把全体数据的最大最小值拿来归一化再做切分,本质上就是偷看了测试集的信息,属于一种隐蔽的数据泄露。我在代码里把scaler.fit()放在训练集切分之后执行,就是为了从源头堵住这个问题。
3. 核心模型与关键实现细节
3.1 模型结构设计
我用LSTM搭建了一个多步预测模型,结构比较简洁但有效:输入层接收形状为(batch_size, seq_len, feature_dim)的张量,其中seq_len是历史窗口长度,feature_dim是特征维度;接着送入两层LSTM,每层隐藏单元数为64;LSTM输出的最后一时间步隐含状态接一个全连接层,输出维度为24,对应未来24小时的负荷预测值。
为什么选两层LSTM而不是单层?单层LSTM对简单周期性模式够用,但负荷序列里有工作日/周末的双周期嵌套,单层结构在捕捉这种嵌套模式时容易力不从心。两层LSTM的堆叠可以让上层学到更高层次的抽象特征,实验下来MAPE能降低0.5到1个百分点。三层以上在这个数据规模上没有明显收益,反而增加训练成本和过拟合风险。
每层LSTM后加了Dropout层,丢弃率设为0.2。Dropout在时序模型里的作用容易被低估,很多人以为它只在CNN/FC里有用,实际上RNN类模型因为参数共享,过拟合问题更隐蔽,Dropout能有效提升泛化能力。不过要注意,Dropout在LSTM里应该加在层与层之间,而不是时间步方向。
3.2 损失函数与评价指标的选择
回归问题的默认损失函数是MSE(均方误差),但在这个项目里,我最终选的是Huber Loss。原因是MSE对异常值极其敏感——如果某一天负荷曲线因为临时限电出现一个极端谷值,MSE会放大这个点对梯度的影响,导致模型为了拟合这个异常点而牺牲正常区段的精度。Huber Loss的特点是误差小于阈值δ时用平方损失,大于δ时用线性损失,对异常值更鲁棒。
评价指标我同时输出MAPE、RMSE和R²。MAPE最直观,业务方容易理解——“平均偏差百分之几”;RMSE对大误差敏感,能体现预测曲线的稳定性;R²反映模型对数据方差的解释程度。实测下来,我这套模型在测试集上的MAPE在3.5%左右,RMSE约为35MW,R²=0.96,峰值时段(上午10点和晚上8点附近)的MAPE略高,约4.8%,符合预期。
3.3 训练策略与关键参数
训练轮数我设为50轮,batch size取64,优化器是Adam,初始学习率0.001。这组参数不是随手敲的,而是在多组实验对比下收敛速度和稳定性都比较均衡的选择。学习率从0.01开始试过,训练震荡很严重,损失曲线像锯齿一样,根本落不下去;降到0.0001又太保守,50轮内还没收敛到理想水平。0.001搭配Adam的默认衰减策略,基本能在25到35轮之间稳定收敛。
我加了一个ReduceLROnPlateau回调,验证集loss连续3轮不下降就直接把学习率减半。这个技巧帮我省了不少事——前期可以大胆用稍高的学习率快速下降,后期自动降低步长微调,不必手动盯着训练曲线反复调整。
还有一个重要的实操细节:梯度裁剪。LSTM在长序列训练时梯度爆炸的风险远高于普通前馈网络,我设置了max_grad_norm=1.0,一旦梯度范数超过这个值就按比例缩放。这个设置让训练过程稳定很多,几乎没有再出现过loss突然跳到NaN的情况。
4. 实操过程与完整实现
4.1 数据集处理与特征工程完整流程
整个代码我按模块化方式组织,核心流程是:加载数据 -> 清洗 -> 特征工程 -> 构建滑窗样本 -> 划分数据集 -> 归一化 -> 训练 -> 评估。
特征工程这一步是重头戏。除了基础的时间特征(小时、星期几、是否节假日),我还构造了滞后特征:前1小时、前24小时、前168小时的负荷值,分别对应短期惯性、日周期性和周周期性。滑动窗口统计特征包括过去24小时的均值、最大值和标准差,这些能反映最近一段时间的负荷水平。
温度特征我做了简单的one-hot分桶处理,按冷暖区间分为“高温”“舒适”“低温”三档。因为原始温度是连续值,和负荷的关系呈现非线性(高温和低温都推高负荷,中间有个谷底),直接在模型里塞连续值反而容易被误解。分桶后模型的规律捕捉能力明显提升,测试集MAPE下降了约0.8个百分点。
4.2 核心代码实现
数据加载与预处理部分我用pandas完成,这部分没什么花活,但每一步都有明确目的。下面给出关键代码段:
import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler # 加载原始数据 df = pd.read_csv('load_data.csv', parse_dates=['datetime']) df.set_index('datetime', inplace=True) df = df.resample('1H').interpolate(method='linear') # 3-sigma异常值处理 for col in ['load']: mean = df[col].mean() std = df[col].std() df.loc[np.abs(df[col] - mean) > 3 * std, col] = np.nan df[col].interpolate(method='linear', inplace=True) # 特征构造 df['hour'] = df.index.hour df['weekday'] = df.index.weekday df['load_lag_1h'] = df['load'].shift(1) df['load_lag_24h'] = df['load'].shift(24) df['load_lag_168h'] = df['load'].shift(168) df['load_mean_24h'] = df['load'].rolling(24).mean() df['load_max_24h'] = df['load'].rolling(24).max() # 温度分桶 df['temp_bin'] = pd.cut(df['temp'], bins=[-10, 10, 28, 45], labels=[0, 1, 2]) # 删除有缺失的行 df.dropna(inplace=True)模型构建和训练部分,核心代码如下:
import torch import torch.nn as nn from torch.utils.data import DataLoader, TensorDataset class LoadForecastLSTM(nn.Module): def __init__(self, input_size, hidden_size, num_layers, output_size, dropout=0.2): super().__init__() self.lstm = nn.LSTM( input_size, hidden_size, num_layers, batch_first=True, dropout=dropout ) self.fc = nn.Linear(hidden_size, output_size) def forward(self, x): out, _ = self.lstm(x) out = self.fc(out[:, -1, :]) return out # 构建滑窗样本 def create_sequences(data, seq_len=168, pred_len=24): X, y = [], [] for i in range(len(data) - seq_len - pred_len): X.append(data.iloc[i:i+seq_len].values) y.append(data.iloc[i+seq_len:i+seq_len+pred_len]['load'].values) return np.array(X), np.array(y) X, y = create_sequences(scaled_df) # 按时间顺序划分,前70%训练,15%验证,15%测试 train_idx = int(len(X) * 0.7) val_idx = int(len(X) * 0.85) # ... 构建DataLoader并训练4.3 训练过程中的现场记录
我实际跑训练时观察到的典型现象可以给读者做参考。前5个epoch,训练loss从0.08快速降到0.03左右,验证集loss也跟着降,说明模型在快速学习负荷的基本周期模式;第10到20个epoch,训练loss继续缓慢下降,但验证集loss在0.015附近波动,存在轻微的过拟合迹象;第20轮之后,随着学习率衰减,验证loss稳定在0.012到0.014之间。
这里有个值得说的现象:验证集loss在训练初期会有一次明显的小幅上升,大概在第3到第5轮之间。很多新手看到loss回升就慌了,以为是模型坏了。实际上这是Adam优化器在调整动量方向时的正常现象,只要后续能回落到更低位,就说明训练没有出问题。我建议的做法是不要过早停止训练,给模型至少15到20轮的观察期。
最终模型在测试集上的预测曲线和真实曲线对比,在大多数时段贴合度很高,尤其是夜间谷段和午间平段。偏差主要出现在两个地方:一是节假日或特殊事件日(比如大型活动、极端天气),模型倾向按历史同期规律预测,导致偏差拉大;二是早晚高峰转换时段(比如早上6到9点),负荷爬坡速度极快,模型预测的坡度比实际略缓。
5. 常见问题与排查技巧实录
5.1 预测结果总是“平滑过头”,峰谷被拉平
这是多步LSTM预测里非常典型的问题。整条预测曲线看起来趋势对,但峰值偏低、谷值偏高,峰谷差明显小于真实数据。原因在于使用MSE/Huber这种逐点损失时,模型学到的是条件均值——在数据分布存在噪声的情况下,条件均值天然会向分布中心收缩,导致预测曲线趋于保守。
解决思路有二。一是调整损失函数,比如引入分位数损失(quantile loss),让模型学会预测条件分位数,预测曲线就不容易被“均值化”拉平。二是训练时对峰谷样本提高权重,让模型更加关注这部分学习难度高的时段。我在实际项目里两个方案都试过,权重调整实现更简单,效果改善明显,峰时MAPE从4.8%降到了4.1%左右。
5.2 训练loss始终不降怎么办
如果训练了好几个epoch,loss仍然在初始值附近震荡,先检查三件事:数据有没有做归一化、输入序列的尺度是否合理、标签有没有和特征一起被归一化。90%的“训不动”问题都出在这三步上。
其次是检查学习率。learning rate太大(比如0.01以上)会导致loss剧烈振荡,像心电图一样高高低低;太小(比如1e-5)则几乎看不到loss下降。建议用0.001作为基线,如果loss曲线是“完全不动”而不是“来回震荡”,可以尝试增大学习率;如果是“振荡但整体不降”,就调低学习率。
最后确认梯度是否消失或爆炸。在代码里打印每个epoch的梯度范数,如果梯度范数为0或者超过100,就需要调整网络层数、检查激活函数、确认梯度裁剪配置是否正确。
5.3 节假日预测怎么处理
这是负荷预测里最经典的难题:节假日负荷模式和平时差异巨大,但一年节假日样本太少,模型很难学到足够的规律。我在这套项目里试过几种思路,效果最好的是加节假日特征并做样本加权——给节假日前后的样本更高的训练权重;其次是单独训练一个节假日修正模型,用少量节假日数据对LSTM的预测结果进行偏差修正。
客观讲,节假日预测想做到精准,需要更长时间的历史数据积累和更多维度的特征(比如节假日类型、调休安排、天气变化),这些已经超出这套基础项目的范围。我的建议是,先把非节假日的预测精度做扎实,再考虑节假日的专项优化。贪多嚼不烂,尤其是单靠一套LSTM想在所有场景通吃的想法,实际项目里很难落地。
5.4 部署时推理速度太慢怎么办
如果训练好的模型要部署到生产环境做在线预测,LSTM推理速度确实是一个需要关注的问题。对于单条预测请求,LSTM的推理延迟通常在几十毫秒级别,一般来说够用;但如果并发量高(比如同时预测几千个用户的负荷曲线),就需要考虑优化。
我实际用过的优化手段包括:ONNX导出加速推理(效果最明显,速度提升2到3倍)、减小序列长度(用96小时代替168小时输入,牺牲一点精度换速度)、批量推理(把多条预测请求合并成一个大batch一次推理)。如果业务对延迟极其敏感,还有一个终极方案是蒸馏——把LSTM的知识蒸馏到一个前馈网络里,虽然损失一点精度,但推理速度可以提升一个数量级。
6. 经验总结与扩展建议
这套负荷预测程序跑通之后,我最大的一点体会是:深度模型在时序预测上并不神奇,它的上限更多取决于数据质量和特征工程,而不是模型结构本身。同样的LSTM,给它干净、特征完备的数据,和给它一条裸负荷曲线喂进去,效果可以差几个百分点。这提醒我在做任何预测项目时,都要把精力优先花在数据理解上。
另一个体会是,不要盲目追求复杂模型。我测试过用Transformer替换LSTM,在同样的数据规模下,Transformer的收敛速度明显更慢,测试集表现也没有超过LSTM——因为数据量根本喂不饱Transformer的参数量。在中小规模数据场景下,轻量模型加上精心的特征设计,往往是性价比最高的方案。
如果后续想扩展这个项目,我建议往这几个方向走:一是增加天气预报数据作为外部输入,尤其是温度、湿度和风速,对夏季和冬季的负荷预测精度提升显著;二是尝试多任务学习架构,同时预测负荷、光伏出力和风电出力,用一个统一的模型处理区域综合能源预测问题;三是加入在线学习机制,让模型在每天拿到新数据后自动做增量更新,保持模型对最新负荷模式的感知能力。数据驱动这条路,一旦把基础框架搭好,后面每一步扩展都能踩在坚实的基石上。
本文还有配套的精品资源,点击获取