时间序列预测神器Prophet python实现
前言
“Prophet” 指的是由 Facebook 开发的一种用于时间序列分析和预测的工具。它设计用于处理每日观测数据,展示不同时间尺度上的模式。Prophet 特别受欢迎的原因之一是其易用性,以及能够建模季节性、假期和特殊事件。Prophet 模型的主要特点包括:
- 季节性:Prophet 能够处理年度、周度和日度季节性,适用于具有周期性模式的时间序列数据
- 假期和特殊事件:模型允许将假期和特殊事件作为额外的输入,以提高预测准确性
- 可调参数:可以调整各种参数以定制模型的行为,例如季节性组件的强度和趋势的灵活性
- 自动检测变点:Prophet 自动识别时间序列中趋势发生显著变化的点
- 加法分量:该模型将时间序列表示为趋势分量、季节性分量和误差项的总和
Prophet 在 R 和 Python 中都有实现,由于其能够以极小的工作量生成准确且易于解释的预测,因此在各个行业中广受欢迎。它被广泛用于金融、电商等领域,这些领域对于决策制定而言,时间序列预测至关重要详细解读网址:
- Github:phet
https://github.com/facebook/prophet
- 官方网址:Prophet | Forecasting at scale. (facebook.github.io)Prophet | Forecasting at scale. (facebook.github.io)://het/
https://facebook.github.io/prophet/
- 论文名字与网址:
https://peerj.com/preprints/3190/
Prophet模型的基本原理涉及将时间序列数据分解为趋势组件、季节性组件和假期效应。以下是Prophet模型的主要公式和基本原理:
- 总体模型Prophet将时间序列 分解为趋势 、季节性 、假期效应 和误差 的和:
- 趋势模型趋势 通常由两部分组成:线性趋势 和饱和增长趋势 ,线性趋势表示长期趋势,而饱和增长趋势用于捕捉可能存在的饱和效应 其中: 表示线性趋势,可以写为 表示饱和增长趋势,采用饱和增长模型,通常用 函数表示
- 季节性模型季节性 由周季节性 和年季节性 组成: 具体形式会根据数据自动适应
- 假期模型假期效应 是用于考虑假期和特殊时间的组件。每个假期 的影响由用户提供,可以是一个二进制的指示符表示是否存在该假期
- 误差模型误差 表示模型无法解释的部分,通常假设为正态分布的噪声
这些组件的具体形式和参数通过拟合模型时从历史数据中学习得到。Prophet利用优化算法来最小化实际观测值与模型预测值之间的误差,从而获得最佳拟合。总体而言,Prophet模型通过这些组件的组合来建模时间序列数据中的趋势、季节性、假期效应和噪声要使用 Prophet,通常需要提供一个包含两列的时间序列数据集:’ds’(日期)和 ‘y’(要预测的值)。然后,可以将模型拟合到历史数据中,进行预测,并可视化结果
代码实现
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
plt.rcParams['font.sans-serif'] = 'SimHei' # 设置中文显示
plt.rcParams['axes.unicode_minus'] = False
data = pd.read_csv('基于KNN临近填补缺失值', index_col=0, parse_dates=['数据时间'])
print(data.shape)
data.head()
数据集为2018-01-01 00:00:00到2021-08-31 23:45:00某地区电网间隔15分钟的负荷数据(数据完整不存在缺失)
plt.figure(figsize=(15,4 ), dpi =300)
plt.grid(True)
plt.plot(data['总有功功率(kw)'], label = '间隔15min数据')
plt.title('间隔15min功率图')
plt.xlabel('时间')
plt.ylabel('总有功功率(kw)')
plt.legend()
plt.show()
# 把数据化为每天的均值数据
data_dmean = data.resample('D').mean()
data_dmean
plt.figure(figsize=(15,4 ), dpi =300)
plt.grid(True)
plt.plot(data_dmean['总有功功率(kw)'], label = '间隔15min数据')
plt.title('每天均值功率图')
plt.xlabel('时间')
plt.ylabel('总有功功率(kw)')
plt.legend()
plt.show()
from fbprophet import Prophet
def FB(datal, column):
df = pd.DataFrame({
'ds':pd.Series(datal.iloc[:,column].index),
'y':pd.Series(datal.iloc[:,column].values)
})
df['cap'] = data.iloc[:,column].max()
df['floor'] = datal.iloc[:,column].min()
m = Prophet(
changepoint_prior_scale = 0.2,
daily_seasonality = False,
yearly_seasonality = True, #年周期性
weekly_seasonality = True, #周周期性
growth = 'linear',
interval_width = 0.8, #置信区间宽度,有多大概率落在浅蓝色线里
)
m.add_country_holidays(country_name = 'CN') # 中国所有节假日
m.fit(df)
future = m.make_future_dataframe(periods = 10) # 往后预测多少
future['cap'] = datal.iloc[:,column].max()
future['floor'] = datal.iloc[:, column].min()
forecast = m.predict(future)
fig1 = m.plot(forecast)
fig2 = m.plot_components(forecast)
return future, forecast
使用Facebook Prophet库进行时间序列预测的Python代码。FB 函数接受一个数据框(datal)和一个列索引(column)作为输入,对数据进行预处理,拟合Prophet模型,然后对未来时间段进行预测
参数 | 含义 |
changepoint_prior_scale | 控制变更点的灵活性,值越大,趋势的灵活性越高 |
daily_seasonality | 是否包含每日季节性,如果为’True’,则考虑每天的季节性波动 |
yearly_seasonality | 是否包含每年季节性,如果为’True’,则考虑每年的季节性波动 |
weekly_seasonality | 是否包含每周季节性,如果为’True’,则考虑每周的季节性波动 |
growth | 指定趋势的增长类型,可以是’linear’或’logistic’ |
interval_width | 置信区间的宽度,用于可视化时显示预测的不确定性 |
holidays | 指定节假日的日期。可以是数据框或’pd.DataFrame’类型,包含节假日的日期和相关信息 |
add_country_holidays | 添加指定国家的所有公共假日 |
seasonality_prior_scale | 控制季节性的灵活性。值越大,季节性的灵活性越高 |
这只是其中一些参数,Prophet 还有其他可调整的参数,具体可以查阅 Prophet 文档 获取详细信息
future, forecast = FB(data_dmean, 0)
plt.figure(figsize=(15,4 ), dpi =300)
plt.grid(True)
plt.plot(data_dmean, color = 'c', label = '日平均功率曲线')
plt.plot(forecast.ds, forecast.yhat, label='预测曲线')
plt.title('实际日平均功率与预测日平均功率对比图')
plt.xlabel('时间')
plt.ylabel('总有功功率(kw)')
plt.legend()
plt.show()
plt.figure(figsize=(15,4 ), dpi =300)
plt.grid(True)
plt.plot(data_dmean[-100:], color = 'c', label = '日平均功率曲线')
plt.plot(forecast.ds[-100-10:], forecast.yhat[-100-10:], label='预测曲线')
plt.title('实际日平均功率与预测日平均功率对比图')
plt.xlabel('时间')
plt.ylabel('总有功功率(kw)')
plt.legend()
plt.show()
from sklearn import metrics
mse = metrics.mean_squared_error(data_dmean.values, np.expand_dims(forecast.yhat.iloc[0:1339].values,axis=1)) # MSE 均方误差
rmse = np.sqrt(mse) # 均方 根误差RMSE
mae = metrics.mean_absolute_error(data_dmean.values, np.expand_dims(forecast.yhat.iloc[0:1339].values,axis=1)) # MAE 平均绝对误差
def mape(y_true, y_pred):
return np.mean(np.abs((y_pred - y_true) / y_true)) * 100
mape = mape(data_dmean.values, np.expand_dims(forecast.yhat.iloc[0:1339].values,axis=1)) # MAPE 平均绝对百分比误差
print(mse)
print(rmse)
print(mae)
print(mape)
from sklearn.metrics import r2_score # 拟合优度
r2_score(data_dmean.values, np.expand_dims(forecast.yhat.iloc[0:1339].values,axis=1))
本文章转载微信公众号@Python机器学习AI