4. 负荷预测基础:经典时间序列模型(ARIMA、SARIMA)原理与实现

说到负荷预测,我入行那会儿可没现在这么多花哨的深度学习工具。那时候,ARIMA 和 SARIMA 就是我们的看家本领。别看它们“老”,在工程实战中,这两个模型依然是很多场景下的首选。为什么?因为稳定、可解释性强,而且数据量不大的时候,效果往往比那些黑盒模型要好。

说白了,负荷预测就是根据过去的数据,猜未来的用电量。你想想看,电网调度、机组启停、市场交易,哪一样离得开这个“猜”字?今天我们就来聊聊这两个经典模型,我会结合我踩过的坑,把原理和代码都掰开揉碎了讲。

核心要点:ARIMA 处理非季节性数据,SARIMA 处理带周期性的数据。电力负荷数据,几乎都有明显的日周期和周周期,所以 SARIMA 更常用。

4.1 从 AR 到 ARIMA:一步步拆解

ARIMA 这个名字,看着挺唬人。其实拆开就是三个部分:AR(自回归)、I(差分)、MA(移动平均)。

  • AR(自回归): 用过去几天的负荷值,来预测今天的负荷。比如,今天上午10点的负荷,跟昨天上午10点的负荷关系很大。这就是自回归的思想。
  • I(差分): 让数据变得平稳。电力负荷数据通常有趋势,比如逐年增长。差分就是让数据“站”在同一个水平线上。我习惯先做一阶差分,看看数据是否平稳。
  • MA(移动平均): 关注的是过去几天的预测误差。说白了,就是修正之前的“猜错”的部分。

这三个部分组合起来,就是 ARIMA(p,d,q)。p 是自回归的阶数,d 是差分的阶数,q 是移动平均的阶数。嗯,这里要注意,这三个参数怎么选,是门学问。

我的经验: 刚开始做项目时,我总想着用 AIC/BIC 准则自动选参。后来发现,在电力负荷预测中,p 和 q 通常不会超过 7(因为一周7天)。手动调参结合 ACF/PACF 图,往往比全自动更靠谱。

4.2 SARIMA:把“周期”这个老朋友请进来

ARIMA 有个硬伤——它处理不了周期性。电力负荷的周期性太明显了:每天一个峰谷,每周一个模式。这时候,SARIMA 就登场了。

SARIMA 在 ARIMA 的基础上,增加了季节性部分。它的完整形式是 SARIMA(p,d,q)(P,D,Q,m)。其中,m 是季节周期长度。对于日负荷数据,m=24(小时周期)或 m=168(周周期,7*24)。

我记得有一次做某工业园区的负荷预测,数据有明显的“周末效应”——周末负荷比工作日低30%。如果只用 ARIMA,预测结果惨不忍睹。换成 SARIMA 后,误差直接降了一半。

避坑指南: 我曾经犯过一个低级错误——把 m 设成了 365(年周期)。结果模型训练了整整两个小时,效果还不好。后来才意识到,对于短期负荷预测(未来几小时到几天),周周期和日周期才是关键。年周期数据量不够,反而会引入噪声。

4.3 核心逻辑:一张图看懂

下面这张图,是我自己总结的 ARIMA/SARIMA 建模流程。每次做项目前,我都会在脑子里过一遍这个流程。

ARIMA/SARIMA 负荷预测建模流程 步骤1:数据准备 缺失值处理、异常值剔除 步骤2:平稳性检验 ADF检验、观察时序图 步骤3:差分处理 确定d和D的值 步骤4 定阶 步骤5:模型拟合 ARIMA/SARIMA 训练 步骤6:残差检验 白噪声检验、Q-Q图 残差是 白噪声? 重新定阶 步骤7 预测输出 注:虚线框表示可选步骤,实际项目中根据数据特性灵活调整

4.4 代码实战:用 Python 实现 SARIMA

理论说完了,咱们直接上代码。我用的是 statsmodels 库,这个库在时间序列分析里算是标配了。

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.statespace.sarimax import SARIMAX
from sklearn.metrics import mean_absolute_error, mean_squared_error

# 1. 加载数据(假设是某地区小时级负荷数据)
df = pd.read_csv('load_data.csv', index_col='time', parse_dates=True)
load = df['load'].values

# 2. 平稳性检验
def test_stationarity(timeseries):
    result = adfuller(timeseries)
    print(f'ADF Statistic: {result[0]:.4f}')
    print(f'p-value: {result[1]:.4f}')
    if result[1] <= 0.05:
        print('数据平稳')
    else:
        print('数据非平稳,需要差分')

test_stationarity(load)

# 3. 一阶差分
load_diff = np.diff(load, n=1)
test_stationarity(load_diff)

# 4. 观察 ACF 和 PACF 图(辅助定阶)
fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(load_diff, lags=40, ax=axes[0])
plot_pacf(load_diff, lags=40, ax=axes[1])
plt.show()

# 5. 拟合 SARIMA 模型
# 参数说明:p=2, d=1, q=2, P=1, D=1, Q=1, m=24(日周期)
model = SARIMAX(load, order=(2, 1, 2), seasonal_order=(1, 1, 1, 24))
results = model.fit(disp=False)
print(results.summary())

# 6. 残差检验
residuals = results.resid
test_stationarity(residuals)

# 7. 预测未来24小时
forecast = results.forecast(steps=24)
print('未来24小时负荷预测值:')
print(forecast)

个人习惯: 我一般会把训练集和测试集分开,用滚动预测的方式验证模型效果。比如用前7天数据预测第8天,然后滑动窗口。这样能更真实地反映模型在工程中的表现。

4.5 参数调优:那些年我踩过的坑

参数调优是 ARIMA/SARIMA 建模中最头疼的部分。我总结了一个“三步走”策略,供你参考:

  1. 先定 d 和 D: 用 ADF 检验确定差分阶数。对于电力负荷,d 通常为 0 或 1,D 通常为 1(因为周周期明显)。
  2. 再看 ACF/PACF 图: ACF 图拖尾、PACF 图截尾,选 AR 模型;反之选 MA 模型。两者都拖尾,选 ARMA。
  3. 最后网格搜索: 在 p、q、P、Q 的小范围内(0-3)做网格搜索,用 AIC 或 BIC 选最优组合。

我曾经踩过的坑: 有一次我为了追求最低的 AIC,把 p 和 q 都设到了 10 以上。结果模型过拟合严重,在测试集上的误差反而比简单模型还大。后来我给自己定了个规矩:p 和 q 不超过 7,P 和 Q 不超过 2。这个经验在大多数电力负荷场景下都适用。

4.6 模型评估:别只看一个指标

评估预测效果,我习惯同时看三个指标:

指标 公式 说明
MAE mean(|实际值 - 预测值|) 平均绝对误差,直观反映误差大小
RMSE sqrt(mean((实际值 - 预测值)²)) 对大误差惩罚更大,适合关注极端情况
MAPE mean(|误差/实际值|) * 100% 百分比误差,适合对比不同量级的数据

我个人最看重 MAPE。为什么?因为电力负荷的峰谷差异很大,MAPE 能告诉你“相对误差”有多大。比如,凌晨低谷时误差 10 MW 和高峰时误差 10 MW,意义完全不同。

工程经验: 对于短期负荷预测(未来1-24小时),MAPE 在 2%-5% 之间算是不错的结果。如果超过 10%,建议检查数据质量或模型参数。我曾经接手过一个项目,MAPE 高达 15%,最后发现是数据采集设备出了故障,导致部分时段数据异常。

好了,ARIMA 和 SARIMA 的核心内容就这些。别看公式复杂,其实用起来就那么几步:数据准备、平稳性检验、差分、定阶、拟合、预测。多做几个项目,你就能找到感觉了。


专注资料整理