本文给出使用 ARIMA 系列模型进行时序分析和预测的示例代码,提供三个实践落地案例。每个案例都将展示常见的数据预处理、模型拟合与调参、以及最终预测和可视化。由于无法在此直接提供真实数据集,这里使用了示例性的数据或说明性代码,读者可根据自己项目的实际数据替换并灵活运用。
在示例中,主要使用 Python 的 statsmodels 库提供的 ARIMA
和 SARIMAX
(季节性 ARIMA)进行时序分析。
目录
- ARIMA 系列模型简介
- 环境准备
- 示例一:单变量日度销量预测
- 示例二:股票价格预测(ARIMA vs. ARMA vs. ARMA+外生变量)
- 示例三:多季节周期下的气温预测(SARIMA)
- 总结与注意事项
1. ARIMA 系列模型简介
ARIMA(AutoRegressive Integrated Moving Average) 模型是一类经典的线性时序分析方法,通过自回归 (AR) 和移动平均 (MA) 两部分,以及对序列做差分 (I) 使其平稳来进行建模。它的主要形式表示为 ARIMA(p, d, q)
:
- p:自回归项 (AutoRegressive) 的阶数。
- d:差分次数 (Integrated)。
- q:移动平均项 (Moving Average) 的阶数。
当数据具有季节性时,可以使用扩展的 季节性 ARIMA,即 SARIMA,表示为 SARIMA(p, d, q)(P, D, Q, m)
,其中 (P, D, Q, m)
为季节周期相关的参数【或使用 statsmodels
中的 SARIMAX
接口】。
ARIMA 主要适用于单一序列的预测,假设序列近似平稳(或通过差分等方式可近似转为平稳)。对于非平稳、强季节性或多元变量的场景,也可以通过 SARIMA(季节性)或 VAR(多元自回归)等其他统计模型进行扩展。
2. 环境准备
以下示例主要使用 Python 及常用数据科学库:
pip install numpy pandas matplotlib statsmodels
- pandas:时序数据读入、处理、操作索引和时间窗口等。
- statsmodels:核心库,用于 ARIMA / SARIMA / VAR 等统计建模。
- matplotlib:绘图展示数据和预测结果。
在实际环境中也可能用到 Jupyter Notebook 以方便可视化和交互式探索。
3. 示例一:单变量日度销量预测
应用场景:假设我们是一家零售电商,记录了每天的商品销量数据 sales
,想要对未来一段时间的销量进行预测,以便备货或制定促销策略。
3.1 数据概览
数据可能包含以下列:
date
:日期,格式如YYYY-MM-DD
sales
:当天的销量数值
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.stattools import adfuller
# ============ 1) 读取数据与初步处理 ============
# 这里假设已经有一个 CSV 文件 "daily_sales.csv",包含 'date' 和 'sales' 两列
df = pd.read_csv("daily_sales.csv", parse_dates=["date"])
df.set_index("date", inplace=True)
# 查看数据前几行
print(df.head())
# 画一下原始销量序列
plt.figure(figsize=(10,4))
plt.plot(df['sales'], label='Daily Sales')
plt.title('Daily Sales Over Time')
plt.legend()
plt.show()
说明:
- 通过
parse_dates
解析日期字段,设置date
列为索引,以便进行时序运算。adfuller
是ADF检验常用函数,可检验序列是否平稳。若不平稳,则ARIMA可能需要差分(d > 0
)。
3.2 平稳性检验与差分
# ============ 2) 平稳性检验(ADF) ============
result = adfuller(df['sales'].dropna())
print("ADF Statistic:", result[0])
print("p-value:", result[1])
# 如果 p-value > 0.05,通常认为序列可能是非平稳的,需要做差分
# 简单示例:做一次差分
df['sales_diff'] = df['sales'].diff()
df['sales_diff'].dropna().plot(title='Diff(1) of Sales')
plt.show()
3.3 模型拟合
- 假设经过1阶差分后,序列平稳。我们可尝试
ARIMA( p=1, d=1, q=1 )
,或通过自动定阶工具(如pmdarima
的auto_arima
)来选择最优参数,这里示例手动指定。
# ============ 3) 构建并拟合 ARIMA 模型 ============
# 假设 d=1, p=1, q=1
model = ARIMA(df['sales'], order=(1,1,1))
model_fit = model.fit()
print(model_fit.summary()) # 查看模型概览
# 4) 对比拟合结果
df['forecast'] = model_fit.fittedvalues
plt.figure(figsize=(10,4))
plt.plot(df['sales'], label='Original')
plt.plot(df['forecast'], label='Fitted by ARIMA(1,1,1)')
plt.title('Daily Sales & Model Fitting')
plt.legend()
plt.show()
3.4 未来预测
- 我们可以预测未来 30 天的销量:
future_steps = 30
forecast_result = model_fit.forecast(steps=future_steps)
print("Forecast for next 30 days:")
print(forecast_result)
# 可视化与历史数据拼接
plt.figure(figsize=(10,4))
plt.plot(df['sales'], label='Historical Sales')
plt.plot(forecast_result, label='Forecast', color='red')
plt.title('Next 30 Days Sales Forecast')
plt.legend()
plt.show()
说明:
model_fit.forecast(steps=...)
用于向未来预测指定步数。- 注意在使用 ARIMA 预测多步时,预测误差会逐步累积;若对较长周期要精确预测,可能需要滚动预测或更复杂模型。
- 对于具有季节性的日度销量(如周末、节假日等模式),可尝试使用
SARIMAX
设置季节周期。
案例启示:
- 当需求相对单一、历史数据较为平稳,可以使用 ARIMA 做快速预测。
- 如果发现显著的周周期、月周期等季节性,可进一步使用 SARIMA 进行改进。
- 也可结合外生变量(如天气、促销活动)作为
exog
拟合(使用statsmodels.tsa.statespace.sarimax.SARIMAX
)。
4. 示例二:股票价格预测
应用场景:对单只股票的价格做简单的ARIMA预测,或者做 ARMA 与外生变量对比。股票价格通常具有一定的随机游走特性,可能需要加差分进行平稳化。
4.1 数据示例
数据格式:
Date
:交易日期Close
:收盘价- (可选外生变量
Volume
等)
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.arima.model import ARIMAResults
df_stock = pd.read_csv("stock_data.csv", parse_dates=["Date"])
df_stock.set_index("Date", inplace=True)
plt.plot(df_stock['Close'])
plt.title("Stock Closing Price Over Time")
plt.show()
4.2 ARMA vs. ARIMA
- 有些股票时序若是随机游走特征,可考虑
ARIMA(0,1,0)
= 随机游走。 - 若数据已接近平稳,可尝试
ARMA
(即ARIMA(p, 0, q)
)。
以 ARMA(1,1)
做演示:
# 假设股价序列差分后更平稳,这里直接对差分序列拟合 ARMA(1,1)
df_stock['diff_close'] = df_stock['Close'].diff()
df_stock['diff_close'].dropna().plot()
plt.title("1st Difference of Closing Price")
plt.show()
# 构建 ARMA(1,1),需要对序列先差分一次(或上面就直接d=1)
diff_series = df_stock['diff_close'].dropna()
model_arma = ARIMA(diff_series, order=(1,0,1)) # (p,d,q) = (1,0,1) => ARMA(1,1) on diff
model_arma_fit = model_arma.fit()
print(model_arma_fit.summary())
注意:statsmodels
中,ARMA 已整合到 ARIMA 中,只是 d=0
的特殊情况,因此可以如上方式构造 ARIMA(diff_series, order=(1,0,1))
。
4.3 ARIMA + 外生变量
有时我们希望利用外生变量(如成交量、宏观经济指标、行业指数等)来协助预测股价。可使用 statsmodels.tsa.statespace.sarimax.SARIMAX
,在参数中指定 exog
。
from statsmodels.tsa.statespace.sarimax import SARIMAX
# 以交易量 'Volume' 作为外生变量
# 由于外生变量的维度必须与主序列对齐,这里仅举例
exog_data = df_stock[['Volume']].iloc[1:] # 与差分后时间对齐
model_exog = SARIMAX(df_stock['diff_close'].dropna(),
order=(1,0,1),
exog=exog_data.dropna()) # 注意对齐索引
model_exog_fit = model_exog.fit()
print(model_exog_fit.summary())
# 预测未来 5 天的差分值 (主序列差分+外生)
# 也需对 exog 进行相应预测或给定未来 Volume 的预估
future_exog = ... # 未来 5 天的成交量预估
pred_diff = model_exog_fit.forecast(steps=5, exog=future_exog)
最后,要把预测到的差分值反推回原始价格:如果 pred_diff
是对价格做的一阶差分预测,需要加回上一天的真实价格累计得出新价格。示例:
# last_real_price 是我们最后一个已知的真实收盘价
last_real_price = df_stock['Close'].iloc[-1]
pred_prices = []
acc_price = last_real_price
for diff_val in pred_diff:
acc_price += diff_val
pred_prices.append(acc_price)
print(pred_prices) # 即未来5天的预测股价
案例启示:
- 股票价格常常具有随机游走特性,纯ARIMA可能难以得到特别好的结果,需要结合更多外生变量或更复杂的非线性模型。
- 当我们使用差分来平稳化时,要注意把预测的差分累加回原值。
- 外生变量有助于改进预测,但要保证其先验可获取(例如下一个交易日的成交量在预测时并不知道,需要估计或另行预测)。
5. 示例三:多季节周期下的气温预测(SARIMA)
应用场景:气温或能源负荷等往往有年季节性和日周期性。比如日平均气温随季节变动明显,还有周或日的波动。采用 SARIMA 可捕捉季节成分。
5.1 数据与可视化
以一份日均气温数据(包含数年)为例,发现其存在年周期性:每年夏季温度高、冬季低。如果还存在更短周期(如一周的模式),则需要额外分析。
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.statespace.sarimax import SARIMAX
df_temp = pd.read_csv("daily_temperature.csv", parse_dates=["date"])
df_temp.set_index("date", inplace=True)
plt.plot(df_temp["temp"])
plt.title("Daily Temperature Over Years")
plt.show()
5.2 SARIMA 参数选择
SARIMA 的形式为 (p,d,q)(P,D,Q,m)
,其中 m
是季节周期长度。
- 若我们认为一年为一个大周期,而数据是日度,那么
m=365
(或 365.25 近似)可能过大,运算量高;很多人根据业务视角,也可能先按月聚合做月度季节性 (m=12) 或周度季节性 (m=52)。这里以 m=365 只作示范。 - 同时检查是否存在周周期 (m=7) 的需求,如果要同时考虑一年季节和每周季节,就需要更复杂的多季节性模型 (TBATS或 statsmodels暂不支持多重季节,或使用
SARIMAX
+ 自定义方法)。
以 (p,d,q) = (1,1,1)
+ (P,D,Q,m) = (1,1,1,365)
做一个简单演示:
# ============ SARIMAX 模型 ============
model_sarima = SARIMAX(df_temp['temp'],
order=(1,1,1),
seasonal_order=(1,1,1,365))
model_sarima_fit = model_sarima.fit(disp=False)
print(model_sarima_fit.summary())
# 预测未来30天温度
future_30 = model_sarima_fit.forecast(steps=30)
plt.figure(figsize=(10,5))
plt.plot(df_temp['temp'], label='Historical Temp')
plt.plot(future_30, label='Forecast', color='red')
plt.title("Temperature Forecast (Next 30 Days)")
plt.legend()
plt.show()
注意:实际中,
m=365
计算量可能不小,也可能过拟合。因此很多人会先对日数据做周或月聚合,或者只保留主要季节成分后再做时序分析。
案例启示:
- 当数据存在明显季节周期时(如日度气温的年周期、月度销售的12月周期),
SARIMA
或者SARIMAX
(带外生变量)常能取得更好结果。 - 对于多重季节周期(如同时存在周周期和年周期)可以尝试TBATS或其他扩展方法;也可分层建模或在深度学习中显式处理。
6. 总结与注意事项
-
ARIMA/SARIMA 适用条件:
- 单一时间序列或少量变量,数据相对稳定、平稳可差分。
- 数据量不需要非常大(相比深度学习,ARIMA可以在相对小规模数据上也能获得不错效果)。
- 对可解释性要求较高,统计理论成熟。
-
差分与平稳:
- 若序列存在趋势、季节性,需要进行差分处理或在季节模型中设置季节差分。
- 可以用 ADF、PACF/ACF 图等辅助判断是否需要差分、以及 AR 和 MA 阶数选择。
-
外生变量 (Exogenous Variables):
SARIMAX
在statsmodels
中可添加exog
,可以利用外部信息(如节假日、营销活动、宏观经济指标等)提升预测精度。- 需确保外生变量在预测时能够提前获取或有合理的预测值。
-
多重季节:
- 如果数据具有多周期(如日度用电量有日周期 + 周周期 + 年周期),ARIMA/SARIMA 可能难以同时兼顾,需要更复杂模型或 TBATS / Prophet / 深度学习等方法。
-
模型评估:
- 通常将历史数据留出一段作为测试集,或使用交叉验证/滚动预测来评估模型。
- 根据评估指标(MAPE, MAE, RMSE 等)和实际业务需求来衡量预测效果。
-
实践与调参:
p, d, q
以及(P, D, Q, m)
的选择需要综合 ACF/PACF 图、信息准则(AIC, BIC)以及自动化调参工具 (pmdarima 的 auto_arima)。- 对应多变量时,也可尝试 VAR、VARMA 等多元模型。
三个 AI 实践落地案例小结
-
日度销量预测(ARIMA)
- 假设历史销量数据具备平稳或可差分的特征,能通过 ARIMA 快速获得短期预测结果,适用于库存与产能规划。
- 如果有明显季节性(如周周期),可尝试 SARIMA。若有节假日或价格等外生因素,还可以引入
exog
。
-
股票价格预测(ARIMA vs. ARMA vs. ARIMA + exog)
- 对金融时间序列进行差分或不差分,然后用 ARMA/ARIMA 做预测,结合成交量或大盘指数等外生变量可以改进预测。
- 要注意股票可能更趋向随机游走,需要更多复杂方法(如GARCH,深度学习)配合。
-
多季节周期的气温预测(SARIMA)
- 对有年周期性的日度气温数据,SARIMA 能捕捉季节趋势。
- 如果还有周周期等多重季节性,可进一步使用复合方法或其他模型。
通过以上三个示例,可以看出 ARIMA 系列(包含 SARIMA)在较多应用场景中皆可灵活使用,尤其在数据规模不大、单一序列或较小维度、多业务需要可解释的场景下,依旧是高效且经典的时序预测方法之一。
【哈佛博后带小白玩转机器学习】 哔哩哔哩_bilibili
总课时超400+,时长75+小时