所有文章 > AI驱动 > ARIMA与Prophet的完美结合:AutoARIMAProphet时序模型
ARIMA与Prophet的完美结合:AutoARIMAProphet时序模型

ARIMA与Prophet的完美结合:AutoARIMAProphet时序模型

AutoARIMAProphet模型

AutoARIMAProphet 是一种将两种流行的时间序列预测模型 AutoARIMA 和 Prophet 结合起来的混合模型。它结合了 AutoARIMA 模型的自动参数选择功能和 Prophet 模型的强大处理非线性趋势和季节性的能力,从而提高了时间序列预测的准确性和鲁棒性

AutoARIMA

AutoARIMA 是一种自动选择最佳ARIMA 模型参数的方法,ARIMA模型通过整合自回归(AR)部分、差分(I)部分和移动平均(MA)部分来进行预测,AutoARIMA 可以通过优化算法自动确定这些参数(p, d, q),从而使模型适应数据的特性,ARIMA模型进阶——具有季节性的SARIMAX模型实现(末尾给出了statsforecast库Github链接这个库除了ARIMA模型自动选择最佳参数以外,还存在其它模型的调用以供读者参考,模型AutoARIMAProphet也将利用这个库实现)

Prophet

Prophet 是由 Facebook 开发的一种时间序列预测模型,设计上特别适合处理具有明显季节性和假日效应的时间序列数据,Prophet 模型基于加法模型,包含趋势、季节性和假日组件,可以灵活地处理缺失数据和异常值,时间序列预测神器Prophet python实现

AutoARIMAProphet 模型工作流程

这样模型构建的优势在于自动化参数选择:利用 AutoARIMA 自动选择最佳参数,减少了模型调参的时间和复杂度,处理非线性趋势和季节性:通过 Prophet 的组件,模型可以有效处理复杂的趋势和季节性模式,鲁棒性:结合两种方法的优点,能够在多种时间序列数据上表现良好

代码构建

数据读取

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

df = pd.read_excel('AutOARIMA-Prophet.xlsx')
df['数据时间'] = pd.to_datetime(df['数据时间']) # 把日期列转换为datetime格式
plt.figure(figsize=(15, 5))
plt.plot(df['数据时间'], df['data'], color='b', alpha=0.6)
plt.title('时序图')
plt.grid(True)
plt.show()

数据准备

# 准备数据,确保日期列名为 'ds',值列名为 'y', 这里主要是去适应模型输入格式
df = df.rename(columns={'数据时间': 'ds', 'data': 'y'})

from sklearn.model_selection import train_test_split
X = df['ds']
Y = df['y']
# 分割训练集和测试集,保留时间序列的顺序shuffle=False
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,test_size = 0.05,
random_state = 0,shuffle=False)
# 合并成一个 DataFrame
train_data = pd.DataFrame({'ds': X_train, 'y': Y_train})
test_data = pd.DataFrame({'ds': X_test, 'y': Y_test})
# 确保索引排序正确
train_data = train_data.sort_index()
test_data = test_data.sort_index()

修改时间序列数据以适应Prophet模型的输入格式,首先将数据框中的日期列名改为’ds’,将值列名改为’y’。然后使用train_test_split函数将数据分割成训练集和测试集,保持时间序列的顺序(即shuffle=False),并将它们组合成两个新的数据框,最后确保了两个数据框的索引排序正确

模型训练

from statsforecast.adapters.prophet import AutoARIMAProphet
from tqdm import tqdm
from datetime import datetime

# 初始化 AutoARIMAProphet 模型配置
model_config = {
"growth": "linear", # 设置增长类型线性增长。适用于数据呈线性增长趋势的情况。
"yearly_seasonality": True, # 启用年度季节性
"seasonality_mode": "multiplicative", # 季节性成分的模式为乘法模式
"seasonality_prior_scale": 10, # 季节性先验尺度
"holidays_prior_scale": 10, # 节假日效应的先验尺度
"changepoint_prior_scale": 0.05, # 变化点的先验尺度
"interval_width": 0.75, # 预测间隔的宽度
"uncertainty_samples": 100 # 用于预测不确定性的样本数量
}
# 实例化模型
model = AutoARIMAProphet(**model_config)

start = datetime.now()
with tqdm(total=1, desc="Fitting Model") as pbar:
autoarimaprophet = model.fit(train_data, disable_seasonal_features=False)
pbar.update(1)
print("Training time:", datetime.now() - start) # 计算训练时间

periods = len(test_data)+30
future_data = autoarimaprophet.make_future_dataframe(periods=periods)
# 进行预测
forecast = model.predict(future_data)
forecast.head()

这里的模型预测将会从测试集的起点开始进行预测,直到定义的往后预测点数量,yhat是预测结果,yhat_lower和yhat_upper是置信区间,下面给出参数解释,具体的参数可参考原文链接

这里模型采用的增长类型是linear如果采用logistic需要指定预测值的上下限,具体代码如下

# 初始化 AutoARIMAProphet 模型配置
model_config = {
"growth": "logistic", # 设置增长类型为逻辑斯蒂增长,适用于 S 形增长的数据
"yearly_seasonality": True, # 启用年度季节性
"seasonality_mode": "multiplicative", # 季节性成分的模式为乘法模式
"seasonality_prior_scale": 10, # 季节性先验尺度
"holidays_prior_scale": 10, # 节假日效应的先验尺度
"changepoint_prior_scale": 0.05, # 变化点的先验尺度
"interval_width": 0.75, # 预测间隔的宽度
"uncertainty_samples": 1000 # 用于预测不确定性的样本数量
}

cap = train_data['y'].max() # 预测值的上限,这里采用测试集的最大值最小值,可根据实际数据进行调整
floor = train_data['y'].min() # 预测值的下限
model = AutoARIMAProphet(**model_config)
# 为训练数据添加 cap 和 floor 列
train_data['cap'] = cap
train_data['floor'] = floor
# 训练模型
start = datetime.now() # 使用datetime模块中的函数获取当前时间
with tqdm(total=1, desc="Fitting Model") as pbar:
autoarimaprophet = model.fit(train_data, disable_seasonal_features=False)
pbar.update(1)
print("Training time:", datetime.now() - start) # 计算训练时间

# 预测未来30天
periods = len(test_data)+30 # 这里时间上是在测试集上进行预测后在往后预测未来30天
future_data = autoarimaprophet.make_future_dataframe(periods=periods)
future_data['cap'] = cap
future_data['floor'] = floor
# 进行预测
forecast = model.predict(future_data)

模型可视化

# 获取最后 30 个预测值
pred = forecast.tail(30)
# 测试集预测
start_date = test_data['ds'].iloc[0]
end_date = test_data['ds'].iloc[-1]
test_pred = forecast[(forecast['ds'] >= start_date) & (forecast['ds'] <= end_date)]
# 训练集预测
start_date = train_data['ds'].iloc[0]
end_date = train_data['ds'].iloc[-1]
train_pred = forecast[(forecast['ds'] >= start_date) & (forecast['ds'] <= end_date)]

plt.figure(figsize=(15, 5))
plt.plot(train_data['ds'], train_data['y'], color='r', alpha=0.3, label='训练集真实值')
plt.plot(test_data['ds'], test_data['y'], color='r', alpha=0.8, label='测试集真实值')

plt.plot(train_pred['ds'], train_pred['yhat'], color='blue', linestyle='--', label='训练集预测值')
plt.fill_between(train_pred['ds'], train_pred['yhat_lower'], train_pred['yhat_upper'], color='blue', alpha=0.2)

plt.plot(test_pred['ds'], test_pred['yhat'], color='green', linestyle='--', label='测试集预测值')
plt.fill_between(test_pred['ds'], test_pred['yhat_lower'], test_pred['yhat_upper'], color='green', alpha=0.2)

plt.plot(pred['ds'], pred['yhat'], color='orange', linestyle='--', label='未来预测值')
plt.fill_between(pred['ds'], pred['yhat_lower'], pred['yhat_upper'], color='orange', alpha=0.2)
plt.title('预测')
plt.legend()
plt.grid(True)
plt.show()

文章转自微信公众号@Python机器学习AI