☰
TensorFlow LSTM短期电力负荷预测实战:从数据到调参
2026/9/29 4:26:45 网站建设 项目流程

简介:这份PDF面向电力系统从业者、深度学习入门者与时间序列预测方向的研究人员,聚焦如何借助TensorFlow构建LSTM循环神经网络,解决短期电力负荷预测精度不足的问题。资源为单文件PDF,压缩包约2.27MB,内容围绕LSTM输入门、输出门与忘记门结构、深度学习特征自动提取、数据迭代与参数更新、模型训练与预测等核心知识点展开,并结合某地区发电厂实际负荷数据设计实验,涵盖时间、节假日、温度、降水量及极端天气等影响因素分析与数据预处理方法。文中通过对比实验说明,基于TensorFlow的LSTM算法预测效果明显优于传统机器学习算法,且随数据量增大展现出良好鲁棒性,可帮助读者理解智能电网与电力系统运行经济化背景下的负荷预测建模思路。目前已有793人学习。

1. 从一份 PDF 说起:TensorFlow 的 LSTM 到底怎么把短期电力负荷预测跑通

很多人第一次搜「基于TensorFlow的LSTM循环神经网络短期电力负荷预测.pdf」,其实是在找一份能直接照着复现的方案,而不是又一篇讲 RNN 门控结构的科普。短期电力负荷预测要解决的是一个很具体的问题:给定过去若干小时或若干天的负荷序列,预测未来 1 小时到 24 小时的用电量,用于机组组合、调度计划和需求侧响应。它的难点不在模型有多深,而在数据周期性强、节假日扰动大、温度等外生变量耦合、以及预测误差直接对应经济成本。LSTM 之所以在这个场景里长期占位,是因为它能通过门控机制保留长距离依赖,把「昨天同一时刻」「上周同一时刻」这类滞后特征自动编码进隐状态,比 ARIMA 更适合多变量、非线性、带缺失的工业序列。这篇笔记按「数据怎么整 → 模型怎么搭 → 参数怎么调 → 坑在哪」的顺序,把一份 PDF 里通常只给结论的东西补成能落地的操作路径,适合已经会一点 Python、想用 TensorFlow 把 LSTM 预测真正跑出可用误差的工程师。

2. 数据准备与特征工程:把负荷序列变成 LSTM 能吃的监督样本

2.1 短期电力负荷预测的数据形态与三个必须处理的特性

电力负荷数据常见形态是 15 分钟或 1 小时采样的单列时间序列,附带温度、湿度、日期类型等外生列。在喂给 LSTM 之前,有三件事必须先处理,否则后面调参全是玄学。

第一是缺失与异常。传感器掉线、通信中断会造成连续 NaN 或恒定值。常见做法是先用线性插值补短缺口,超过 4 个连续点的缺口用「同星期同小时均值」填充,再用 3σ 或 IQR 把明显偏离的尖峰标记为异常并替换。不要直接dropna(),那会把节假日的关键样本删掉。

第二是周期性编码。小时、星期、月份这些离散时间特征如果直接当数值喂进去,模型会误以为 23 点和 0 点距离很远。标准做法是做 sin/cos 周期编码:

import numpy as np import pandas as pd def add_cyclical_features(df, col, period): # col: 时间列名, period: 周期长度(小时=24, 星期=7) df[f'{col}_sin'] = np.sin(2 * np.pi * df[col] / period) df[f'{col}_cos'] = np.cos(2 * np.pi * df[col] / period) return df df = pd.read_csv('load.csv', parse_dates=['timestamp']) df['hour'] = df['timestamp'].dt.hour df['weekday'] = df['timestamp'].dt.weekday df = add_cyclical_features(df, 'hour', 24) df = add_cyclical_features(df, 'weekday', 7)

逻辑说明:sin/cos 把周期首尾接上,让 23 点和 0 点在特征空间里相邻。参数说明:period必须与真实周期一致,小时用 24,星期用 7,月份用 12;如果数据是 15 分钟粒度,小时周期要改成 96。

第三是归一化。负荷和温度量纲差异大,必须分别做 Min-Max 或 Z-score。注意归一化参数只能用训练集拟合,再 transform 验证集和测试集,否则会引入未来信息,这是最常见的翻车点之一。

2.2 用滑动窗口构造监督学习样本

LSTM 的输入是三维张量(样本数, 时间步, 特征数)。短期负荷预测一般用过去 24 到 168 个时间步预测未来 1 到 24 步。下面这个函数把单表转成X, y:

def make_windows(data, target_col, input_len, output_len, feature_cols): # data: 归一化后的 DataFrame # input_len: 历史窗口长度, output_len: 预测步长 X, y = [], [] values = data[feature_cols].values target = data[target_col].values for i in range(len(data) - input_len - output_len + 1): X.append(values[i:i + input_len]) y.append(target[i + input_len:i + input_len + output_len]) return np.array(X), np.array(y) FEATURES = ['load', 'temp', 'hour_sin', 'hour_cos', 'weekday_sin', 'weekday_cos'] X, y = make_windows(train_df, 'load', input_len=48, output_len=1, feature_cols=FEATURES) print(X.shape, y.shape) # (N, 48, 6) (N, 1)

逻辑说明:input_len=48表示用过去 48 小时预测下一小时,适合捕捉两天的日周期;output_len=1是单步预测,若要做 24 小时日前预测就改成 24。参数说明:feature_cols必须包含目标列本身,否则模型看不到历史负荷;窗口切分只能在训练集内部做,验证集和测试集要按时间顺序切,不能随机 shuffle。

2.3 训练集、验证集、测试集的时间切分原则

时间序列不能随机划分。常见做法是按 7:1.5:1.5 或 8:1:1 沿时间轴切,且验证集用于早停和调参,测试集只在最后用一次。如果数据跨年,最好保证每个集合都覆盖完整季节,否则模型会在测试集上遇到没见过的冬季高峰。切分后各自做窗口构造,不要先构造窗口再切,那样会造成窗口跨集合泄漏。

3. TensorFlow 里搭一个能收敛的 LSTM 预测网络

3.1 用 Keras 函数式 API 定义多变量 LSTM

TensorFlow 2.x 推荐用 Keras。下面是一个适合短期负荷预测的基线结构:两层 LSTM 加 Dropout,再接全连接输出。

import tensorflow as tf from tensorflow.keras import layers, models def build_lstm_model(input_len, n_features, output_len): inputs = layers.Input(shape=(input_len, n_features)) x = layers.LSTM(64, return_sequences=True)(inputs) x = layers.Dropout(0.2)(x) x = layers.LSTM(32)(x) x = layers.Dropout(0.2)(x) x = layers.Dense(32, activation='relu')(x) outputs = layers.Dense(output_len)(x) model = models.Model(inputs, outputs) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3), loss='mse', metrics=['mae'] ) return model model = build_lstm_model(48, len(FEATURES), 1) model.summary()

逻辑说明:第一层 LSTM 设return_sequences=True把每个时间步的隐状态传给第二层,第二层只取最后一步输出。Dropout 放在两层之间抑制过拟合。参数说明:64/32是隐单元数,负荷预测这种量级通常 32 到 128 够用,再大容易过拟合;learning_rate=1e-3是 Adam 的稳妥起点,若 loss 震荡就降到 5e-4。

3.2 训练循环、早停与学习率调度

训练时用EarlyStopping和ReduceLROnPlateau两个回调,能省掉大量手动试错:

callbacks = [ tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=10, restore_best_weights=True), tf.keras.callbacks.ReduceLROnPlateau( monitor='val_loss', factor=0.5, patience=5, min_lr=1e-5) ] history = model.fit( X_train, y_train, validation_data=(X_val, y_val), epochs=100, batch_size=64, callbacks=callbacks, verbose=1 )

逻辑说明:patience=10表示验证损失连续 10 轮不降就停并回滚到最优权重;ReduceLROnPlateau在 5 轮不降后把学习率减半。参数说明:batch_size=64对几千到几万样本比较稳,样本少就降到 32;epochs=100只是上限,实际由早停决定。

3.3 评估指标:别只看 MSE

负荷预测的业务误差通常看 MAPE 和 RMSE。MAPE 在负荷接近零时会被放大,所以夜间低谷时段要单独看。下面这段把预测值反归一化后算指标:

from sklearn.metrics import mean_absolute_error, mean_squared_error def inverse_transform(scaler, arr): return scaler.inverse_transform(arr.reshape(-1, 1)).flatten() pred = model.predict(X_test) pred_inv = inverse_transform(load_scaler, pred) true_inv = inverse_transform(load_scaler, y_test) rmse = np.sqrt(mean_squared_error(true_inv, pred_inv)) mape = np.mean(np.abs((true_inv - pred_inv) / true_inv)) * 100 print(f'RMSE={rmse:.2f}, MAPE={mape:.2f}%')

逻辑说明:反归一化必须用训练集拟合的 scaler,否则数值没有物理意义。参数说明:MAPE 低于 3% 在日前预测里算不错,低于 2% 属于优秀;如果 MAPE 正常但夜间 RMSE 偏高,说明模型对低谷段欠拟合,需要加样本权重或单独建模。

4. 调参与排错:短期负荷预测里最容易翻车的五个地方

4.1 现象:验证 loss 一直不降,训练 loss 也高

原因通常是学习率过大或输入特征没归一化。先检查X_train的均值和方差,如果某些列量级差两个数量级以上,LSTM 的梯度会被主导。解决:对所有特征做 Z-score,学习率从 1e-3 降到 3e-4,并确认窗口构造没有把 NaN 带进去。

4.2 现象:训练 loss 很低,测试集 MAPE 突然飙到 10% 以上

这是典型过拟合或数据泄漏。先查是否随机 shuffle 了时间序列,再查归一化是否用了全量数据拟合。解决:改成时间顺序切分,归一化只在训练集 fit;把 LSTM 单元数减半,Dropout 提到 0.3,并增加早停耐心值。

4.3 现象:预测曲线整体滞后一小时

原因多半是窗口对齐错了。y的起点应该是i + input_len,如果写成i + input_len - 1就会把当前时刻当成预测目标,造成「预测值等于上一时刻」的假象。解决:打印几组X[-1]和y对照时间戳,确认目标确实是未来时刻。

4.4 现象:节假日误差爆炸

原因:模型没见过春节、国庆这种负荷骤降模式,周期编码也无法表达。解决:加is_holiday二值特征,或对节假日样本单独加权;如果数据够,训练一个节假日专用模型,平时模型和节假日模型按日历切换。

4.5 现象:GPU 显存够但训练极慢

原因:batch_size太小或数据管道在 Python 里逐条生成。解决:把X_train转成tf.data.Dataset并加.cache().prefetch(tf.data.AUTOTUNE),batch 提到 128 或 256,同时确认没有在fit里开validation_split又手动传验证集造成重复计算。

5. 把单步预测扩成 24 小时日前预测的两个实用技巧

5.1 直接多输出与滚动预测的取舍

单步模型扩到 24 步有两条路。直接多输出是把output_len设成 24,一次吐出全天曲线,训练快、误差不会累积,但输出之间缺少显式约束。滚动预测是用预测值喂回输入逐步推 24 次,能利用最新信息,但误差会累积,且推理慢 24 倍。我的习惯是先用直接多输出做基线,如果日前 MAPE 比单步高不超过 1 个百分点,就不折腾滚动。

# 直接多输出:只改 output_len X, y = make_windows(train_df, 'load', input_len=48, output_len=24, feature_cols=FEATURES) model = build_lstm_model(48, len(FEATURES), 24)

参数说明:output_len=24时最后一层 Dense 输出 24 维,损失仍是 MSE,但建议改成对高峰时段加权,因为高峰误差的经济代价更大。

5.2 用残差修正和分位数损失提升可用性

如果直接多输出在高峰段仍偏差大,可以训练一个残差模型:先用基线模型预测,再把残差当新目标训一个小 LSTM 做修正。另一个技巧是把损失换成分位数损失,输出 P10/P50/P90 三条曲线,调度侧能按风险偏好选点。下面是一个分位数损失的实现:

def quantile_loss(q): def loss(y_true, y_pred): e = y_true - y_pred return tf.reduce_mean(tf.maximum(q * e, (q - 1) * e)) return loss # 输出三个分位数需要三个输出头或输出维度=3 model.compile(optimizer='adam', loss=quantile_loss(0.5))

逻辑说明:q=0.5就是 MAE,q=0.9会惩罚低估更多,适合保守调度。参数说明:分位数模型要分别训 0.1、0.5、0.9 三个头,或把输出维度设成 3 并在 loss 里按列计算。

5.3 上线前必须做的一次回测

模型在测试集上好看不代表能上线。上线前用最近三个月做一次滚动回测:每天用当天之前的数据重训或微调,预测次日 24 点,统计每日 MAPE 的均值和 95 分位。如果 95 分位超过业务容忍线,说明模型对极端天气或节假日不稳,需要补特征或加集成。我自己的习惯是回测至少覆盖一个季节切换,否则不敢把模型接到调度侧。这套流程从数据到回测跑通大概两三天,真正花时间的是特征和排错,不是搭网络。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询