尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

时间序列预测实战:LSTM、ARIMA与AutoTS在电力负荷预测中的选型

时间序列预测实战:LSTM、ARIMA与AutoTS在电力负荷预测中的选型 简介基于第十届泰迪杯B题电力系统赛题整理的全国三等奖完整方案面向数据挖掘、机器学习方向的竞赛选手与电力负荷预测研究者。资源覆盖从数据清洗、缺失值填补、异常值检测到多尺度负荷预测的完整流程分别用LSTM、ARIMA、AutoTS三类时序模型构建方案并输出MAE等多指标评价结果与突变量级分析可视化部分基于Seaborn、Plotly、Matplotlib绘制包含数据分布、箱线图、热力图与预测对比图可直接对照复现。压缩包共86个文件大小15.27MB以可视化图表45张png、预测数据表csv/xlsx、Python代码py/ipynb为主体另附模型结果txt、赛题说明pdf、总结文档docx以及处理后中间数据与最终预测结果目录结构清晰。当前已有2327人浏览学习适合需要系统掌握电力负荷预测建模、时间序列特征工程、异常值处理与竞赛报告写作的读者也便于后续改进模型或迁移到其他负荷预测场景。1. 电力系统负荷预测赛题里LSTM、ARIMA与AutoTS怎么选第十届泰迪杯B题给出的数据并不复杂区域15分钟负荷、行业日负荷、每天最大最小负荷外加一份气象数据。但真正动手后会发现附件里的时间戳有重复、气象字段有缺失直接套模型的结果惨不忍睹。这套国三代码的核心价值在于它把一条完整的预测链路拆成了数据清洗、特征重采样、三类模型对照、多指标评估和可视化验证而不是只给一个能跑的LSTM脚本。如果你正在准备数据挖掘竞赛或者需要处理电力系统负荷预测的可复现流程这包资料值得拆开看一遍。下面按实际顺序讲清每一步的选型逻辑和关键参数重点说明哪些地方容易掉坑以及为什么同一份数据要备三套模型。2. 数据清洗与特征重采样先解决15分钟负荷序列的脏数据2.1 缺失值与重复值处理附件1.1是区域15分钟负荷预测数据一天有96个记录点。原始数据里存在两类典型问题一是同一时间出现多条记录二是某些时刻完全缺失。资料里的“15mins数据缺失值.txt”和“气象数据重复值.txt”就是在排查这两类问题。处理顺序应该先去重再插值否则重采样时会统计出虚高或虚低的值。import pandas as pd df pd.read_csv(附件1.1-区域15分钟负荷预测数据.csv, parse_dates[时间]) df df.set_index(时间).sort_index() # 去掉重复时间戳保留每个时刻最后一条记录 df df[~df.index.duplicated(keeplast)] # 统计缺失情况 print(df.isna().sum()) # 线性插值连续缺失不超过2个点时填补 df df.interpolate(methodlinear, limit2, limit_areainside)这里keeplast表示同一个时间点有多条数据时保留最后写入的那条。limit2是防止连续缺失过长时线性插值造出一段虚假的直线。limit_areainside会让序列两端的缺失保留原样因为外推没有依据。对15分钟负荷序列来说单点缺失用线性插值很安全因为相邻时刻负荷变化相对平滑。2.2 突变单位与IQR异常值过滤负荷数据里偶尔会出现同一个时刻电压、电流记录异常导致的负荷跳变。资料中同时存在“3倍四分位距处理异常值.png”和“1.5倍四位分距处理异常值.png”两张图说明当时对比过两种阈值。对电力负荷而言1.5倍IQR会把正常的峰谷波动也识别成异常3倍IQR更合适。计算方式是对相邻时刻负荷差值的绝对值做分位数过滤。def filter_outlier_by_iqr(series, k3): q1 series.quantile(0.25) q3 series.quantile(0.75) iqr q3 - q1 lower q1 - k * iqr upper q3 k * iqr return series.clip(lower, upper) # 计算突变单位相邻时刻负荷差的绝对值 load df[负荷值] diff_abs load.diff().abs().dropna() diff_filtered filter_outlier_by_iqr(diff_abs, k3)k3时只有距离四分位距3倍以上的突变才会被拉回边界。实际操作中我会先看diff_abs.describe()如果最大突变超过上界很多再决定是否用3倍还是2.5倍。注意clip是把越界值拉回到边界而不是删除这样能保留时间序列长度LSTM训练时不需要处理样本缺失。2.3 最大最小值重采样与数据对齐附件1.2要求预测区域每天最大最小负荷但原始分钟数据是15分钟粒度所以需要把15分钟数据按天聚合。资料里的“最大值重采样以及相应时间.xlsx”和“最小值重采样以及相应时间.xlsx”就是这一步生成的。聚合时除了取最大值还要记录最大值出现的时刻因为“几点钟出现峰值”本身就是强特征。原始数据聚合粒度聚合方式输出15分钟负荷小时max / min / mean小时负荷特征15分钟负荷天max / min每日最大最小负荷气象数据天mean / max日温度、风力特征daily df.resample(D).agg( load_max(负荷值, max), load_min(负荷值, min), load_mean(负荷值, mean) ) # 记录极值出现时间 daily[max_time] df.resample(D)[负荷值].idxmax() daily[min_time] df.resample(D)[负荷值].idxmin()resample(D)按天聚合agg里用元组指定新列名和统计量。idxmax()返回最大值对应的原始时间戳这个时间戳转换成小时、分钟之后可以作为循环特征。聚合后的日数据再和附件3的气象数据按日期合并就得到第二问的完整训练集。3. LSTM、ARIMA与AutoTS三个模型的定位与代码实现3.1 为什么同一道题需要三套模型第一问要求预测未来10天区域15分钟负荷输出960个点属于细粒度长序列预测LSTM比ARIMA更容易学习到一天96个点的周期性。第二问要求预测行业日负荷和每天最大最小负荷样本量小AutoTS更容易在多种统计模型之间找到合适基线。ARIMA则用来做对照实验验证LSTM的增益是否真实存在。资料里把“ARIMA模型第一大题第1小问.py”“AutoTS模型第一大题第1、2小问.py”分开写目的就是让每个模型都能独立跑通并输出评价指标。3.2 ARIMA自动定阶与周期参数ARIMA模型最大问题是手动定阶困难所以代码里用pmdarima的auto_arima自动搜索。关键参数不是p、q而是seasonal和m。15分钟数据一天有96个点m96代表日周期日粒度数据则m7代表周周期。from pmdarima import auto_arima # train_series 是训练集负荷序列freq 为 15min model auto_arima( train_series, start_p0, max_p5, start_q0, max_q5, dNone, # 自动确定差分阶数 seasonalTrue, m96, # 15分钟数据日周期为96 stepwiseTrue, traceTrue, error_actionignore, suppress_warningsTrue ) # 预测未来10天即96 * 10 个点 forecast model.predict(n_periods960)dNone让函数通过ADF检验自动决定差分阶数这是避免人工判断平稳性的捷径。m96如果设错模型会以为周期是7天导致季节差分完全错位。traceTrue会把搜索过程打印出来方便看最终选择了哪个阶数。注意ARIMA不支持多变量气象特征如果硬要加入温度、湿度需要用带外生变量的ARIMAX。3.3 LSTM模型的输入构造与训练LSTM脚本的核心是把多变量序列转换成滑动窗口样本。第一问输入过去一天96个时刻的特征预测未来1个时刻的负荷推理时把预测值拼回输入再滚动预测下一个点最终得到960步预测。from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense from sklearn.preprocessing import MinMaxScaler cols [load, temp, wind, hour_sin] data df[cols].values scaler MinMaxScaler() scaled scaler.fit_transform(data) def create_dataset(data, input_steps96, output_steps1): X, y [], [] for i in range(len(data) - input_steps - output_steps 1): X.append(data[i:i input_steps]) y.append(data[i input_steps:i input_steps output_steps, 0]) return np.array(X), np.array(y) X, y create_dataset(scaled, input_steps96, output_steps1) model Sequential([ LSTM(64, return_sequencesFalse, input_shape(X.shape[1], X.shape[2])), Dense(1) ]) model.compile(optimizeradam, lossmse) model.summary()input_steps96表示用过去96个15分钟点预测下一个点。output_steps1是当前窗口输出一个值。return_sequencesFalse表示只取最后一个LSTM单元的隐藏状态输出。训练时不要对序列做随机shuffle否则时间顺序会被打乱验证集也会看到未来信息。from tensorflow.keras.callbacks import EarlyStopping early_stop EarlyStopping(monitorval_loss, patience5, restore_best_weightsTrue) history model.fit( X_train, y_train, epochs100, batch_size64, validation_split0.2, callbacks[early_stop] )validation_split0.2会从训练数据末尾切出20%作为验证集Keras对时间序列不会打乱这正好符合时序验证的要求。patience5表示验证loss连续5轮不下降就停止避免浪费算力。3.4 AutoTS自动选择基线模型第二问数据量小直接堆LSTM容易过拟合。AutoTS的定位是自动搜索ARIMA、Prophet、指数平滑等模型并给出一个ensemble结果。代码里“AutoTS模块第二大题第2小问.py”处理日负荷预测任务。from autots import AutoTS model_autots AutoTS( forecast_length10, # 预测未来10天 frequencyD, # 输入数据为日粒度 ensembleauto, max_generations5, num_validations2, verbose0 ) model_autots.fit(training_data, date_coldate, value_colload) pred model_autots.predict() forecast_df pred.forecastforecast_length必须和赛题要求一致第二问问未来10天这里就是10。max_generations5时搜索深度适中比赛环境建议不要超过10否则一次训练可能跑几个小时。num_validations2表示用前两段数据做回测验证AutoTS会自动选择在回测上表现最好的模型。3.5 两个问题之间的建模差异赛题问题预测对象时间粒度推荐模型输出长度第一问区域15分钟负荷15分钟LSTM / ARIMA960个点第二问行业日负荷天AutoTS / LSTM10个点第二问补充每天最大最小负荷天聚合后再预测10个点第一问的960个点直接预测容易累积误差代码里采用滚动预测每次预测1步把结果追加到输入窗口再预测下一步。第二问由于预测步数短AutoTS直接输出10个点即可。这种分工避免了一个模型硬吃两种不同粒度的数据。4. 多指标模型评价与可视化剖析4.1 MAE、RMSE、MAPE指标实现赛题评价不会只看MSE所以代码里单独放了一个“MAE等多指标模型评价代码实现.txt”。实际评价时MAE衡量平均绝对偏差RMSE放大极端误差MAPE衡量百分比误差R2作为参考。from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score import numpy as np def evaluate_forecast(y_true, y_pred): y_true np.asarray(y_true).ravel() y_pred np.asarray(y_pred).ravel() mae mean_absolute_error(y_true, y_pred) rmse mean_squared_error(y_true, y_pred) ** 0.5 mape np.mean(np.abs((y_true - y_pred) / y_true)) * 100 r2 r2_score(y_true, y_pred) return { MAE: round(mae, 4), RMSE: round(rmse, 4), MAPE(%): round(mape, 4), R2: round(r2, 4) } # 示例输出 metrics evaluate_forecast(y_test, y_pred) print(metrics)当真实负荷接近0时MAPE会变得很大所以有些队伍会过滤掉凌晨负荷小于阈值的点再算MAPE。这里ravel()是把预测结果展平为一维防止传入形状不对的数组导致维度错误。4.2 用热力图排查特征相关性可视化文件夹里大量热力图比如“全部特征及完整热力图.png”“weather相关性热力图.png”这些图不是赛后补的而是建模前的筛选工具。如果温度和湿度相关系数超过0.9两个特征同时输入LSTM会导致冗余降低模型泛化能力。import seaborn as sns import matplotlib.pyplot as plt features [load, temp_max, temp_min, wind, humidity] corr df[features].corr(methodpearson) plt.figure(figsize(10, 8)) sns.heatmap( corr, annotTrue, fmt.2f, cmapcoolwarm, linewidths0.5, squareTrue ) plt.title(Feature Correlation Heatmap) plt.savefig(weather相关性热力图.png, dpi200, bbox_inchestight)annotTrue在每个格子里显示相关系数fmt.2f控制小数位数。squareTrue让格子保持正方形适合热力图排版。观察热力图时我会优先看负荷列与其他气象特征的相关系数负荷与温度通常呈负相关与湿度呈正相关。找出强相关特征对之后只保留其中一个或者用PCA做主成分提取。4.3 折线图、箱线图和HTML交互图资料里有“各行工业总折线图.png”“商业最大值最小值箱线图.png”“大工业.html”等文件。折线图用于看日负荷曲线的双峰形态箱线图用于看不同行业的负荷分布差异HTML文件则是用plotly生成的交互图。import plotly.express as px # 按小时聚合绘制不同行业的负荷曲线 fig px.line( df_hourly, xhour, yload, colorindustry, title不同行业小时负荷曲线 ) fig.write_html(各行业小时负荷曲线.html) # 箱线图看大工业负荷分布 fig2 px.box( df[df[industry] 大工业], xweekday, yload, title大工业周内负荷分布 ) fig2.write_html(大工业周内负荷分布.html)plotly的HTML文件可以直接放大、悬停查看数值比静态PNG更适合排查异常点。折线图如果发现某个时刻负荷突然掉到接近0很可能是缺数被填成了0要回溯原始数据。箱线图则能直观显示每个行业是否有明显的春节、国庆断崖式下跌。4.4 损失函数曲线与过拟合判断“全部数据损失函数下降初始模型.png”和“最终模型.png”是两组不同阶段的训练曲线。对比它们能发现最终模型验证loss更早收敛且与训练loss差距更小。这里有一个容易忽略的点训练LSTM时确认过validation_split是否切在时间序列尾部而不是随机切分。plt.plot(history.history[loss], labeltrain loss) plt.plot(history.history[val_loss], labelval loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(第二问损失函数.png)如果验证loss先下降后快速反弹说明模型已经开始记忆噪声这时应该减小LSTM单元数或者增大dropout。如果验证loss始终高于训练loss且保持平行说明数据分布差异不大可以继续训练。5. 复现时最难发现的5个细节最后放一组实战注意点都是这包代码里踩过、后续验证过的位置。照做能少花很多无用功。细节1LSTM训练时不要shuffle数据。很多入门代码里model.fit默认shuffleTrue这会将时间顺序打乱导致LSTM学不到先后依赖关系。传shuffleFalse并让验证集来自时间序列尾部。细节2时间特征要做周期编码。小时、星期几这类型特征不能直接填0到23或1到7的数字应该用sin/cos变换让0点和23点在距离上相邻。hour df.index.hour omega 2 * np.pi / 24 df[hour_sin] np.sin(omega * hour) df[hour_cos] np.cos(omega * hour)很多做时序预测的团队会忽略这一步直接用原始小时数值导致LSTM认为0点和23点数值距离很远。细节3预测未来960个点时必须滚动预测。一次性输出960个点LSTM会失去逐步纠错能力。正确做法是用96个历史点预测1个点把这个点拼到历史窗口里再预测下一个点。代码里“全部数据初始模型未来960预测.png”就是这么生成的。细节4反归一化时只还原负荷列。训练时对多列特征一起归一化预测输出也是归一化后的值此时需要取出优化器里保存的负荷列的min和max做反变换。如果误把整个特征矩阵的scaler拿来做单列反归一化预测结果会完全错位。load_min scaler.data_min_[0] # 负荷列是第一个特征 load_max scaler.data_max_[0] y_pred_real y_pred * (load_max - load_min) load_minscaler.data_min_和data_max_分别保存每个特征列的原始最小值和最大值。下标0对应构造scaled时负荷列所在的位置如果特征顺序变了需要同步调整。细节5输出文件的时间对齐。附件要求提交的预测表里时间列必须从测试集起始点开始逐行递推。很多复现跑出的预测曲线很漂亮但提交时发现行数差1个点原因是没有把起始时间索引对上。合并气象预测数据时用pd.date_range(starttest_start, periods960, freq15min)重新生成时间列再直接写入CSV比从原数据拷贝索引更可靠。本文还有配套的精品资源点击获取
返回列表