prophet是facebook开源的一个时间序列预测算法。
1、简介:时间序列预测算法Prophet是Facebook团队开源的一个时间序列预测算法,该算法结合了时间序列分解以及机器学习算法,并且可以对存在缺失值和异常值的时间序列进行预测。
2、安装:
使用conda命令:(如果没有安装anaconda请查看我的另一篇文章:Anaconda以及一些常用操作.)
conda install pystan
conda install -c conda-forge prophet
适用于有明显内在规律的、周期性的数据,比如说季节性变化,节假日趋势。
黑色的点:表示原始的时间序列离散点
深蓝色的线:表示使用时间序列来拟合所得到的取值
浅蓝色的线:表示时间序列的一个置信区间,也就是所谓的合理的上界和下界
Prophet模型的输入输出:输入已知的时间序列的时间戳和相应的值;输入需要预测的时间序列的长度;输出未来的时间序列走势。输出结果可以提供必要的统计指标,包括拟合曲线,上界和下界等。
传入prophet的数据:分为两列,ds和y,ds表示时间序列的时间戳(是pandas的日期格式),y表示时间序列的取值(数值型数据),Prophet的默认字段,必须用命名为ds和y这两列。一般情况下,y要进行归一化
df['y'] = (df['y'] - df['y'].mean()) / (df['y'].std())
prophet输出的预测值:yhat,表示时间序列的预测值;yhat_lower,代表的是预测值的下界;yhat_upper,代表的是预测值的上界。
1、原理:由于现实中,时间序列常常是由趋势项,季节项,节假日效应和突发事件以及残差项组成,所以Prophet算法采用了时间序列分解的方法,它把时间序列分为了这几个部分:
y ( t ) = g ( t ) + s ( t ) + h ( t ) + α y(t)=g(t)+s(t)+h(t)+α y(t)=g(t)+s(t)+h(t)+α
其中的 g ( t ) g(t) g(t)表示趋势项,它体现了时间序列的非周期变化趋势; s ( t ) s(t) s(t)表示季节项,它体现了时间序列的周期性变化,如每周,每年的这种季节性变化; h ( t ) h(t) h(t)表示节假日项,它体现了节假日等持续一天到几天的无规律变化;最后的 α α α表示残差项,通常是正态分布的。然后各项分别被拟合,最后的累加结果即是Prophet算法的预测结果。
2、优点:
(1)、测量数据不需要有规律的间隔。
(2)、我们不需要插入缺失的值或者是删除离群值, 即Prophet对缺失值友好,对异常值敏感。
(3)、预测模型的参数很容易解释。
3、其他调优策略
(1)、模型默认是按照线性趋势增长的,但是如果按照log方式增长,可以调节growth = ‘logistic’, 逻辑回归模型。
(2)、当我们预先知道某天会影响数据的整体走势,可以将此天设置为转折点。
(3)、针对节假日,可以通过holday来进行调节,针对不同的假期,可以调整不同的前后窗口期。例如:春节有7日,但是春运影响将近30日。
Prophet的默认参数:
def __init__(
self,
growth='linear',
changepoints=None,
n_changepoints=25,
changepoint_range=0.8,
yearly_seasonality='auto',
weekly_seasonality='auto',
daily_seasonality='auto',
holidays=None,
seasonality_mode='additive',
seasonality_prior_scale=10.0,
holidays_prior_scale=10.0,
changepoint_prior_scale=0.05,
mcmc_samples=0,
interval_width=0.80,
uncertainty_samples=1000,
):
1、growth:增长趋势模型,分为“linear”与“logistic”,分别代表线性与非线性的增长,默认值为linear。
2、Capacity:在增量函数是逻辑回归函数的时候,需要设置的容量值,表示非线性增长趋势中限定的最大值,预测值将在该点达到饱和.
3、Change Points:可以通过 n_changepoints 和 changepoint_range 来进行等距的变点设置,也可以通过人工设置的方式来指定时间序列的变点,默认值:“None”.
4、n_changepoints:用户指定潜在的”changepoint”的个数,默认值:25。
5、changepoint_prior_scale:增长趋势模型的灵活度。调节”changepoint”选择的灵活度,值越大,选择的”changepoint”越多,从而使模型对历史数据的拟合程度变强,然而也增加了过拟合的风险。默认值:0.05。
6、seasonality_prior_scale(seasonality模型中的):调节季节性组件的强度。值越大,模型将适应更强的季节性波动,值越小,越抑制季节性波动,默认值:10.0.
7、holidays_prior_scale(holidays模型中的):调节节假日模型组件的强度。值越大,该节假日对模型的影响越大,值越小,节假日的影响越小,默认值:10.0。
8、freq:数据中时间的统计单位(频率),默认为”D”,按天统计.
9、periods:需要预测的未来时间的个数。例如按天统计的数据,想要预测未来一年时间内的情况,则需填写365。
10、mcmc_samples:mcmc采样,用于获得预测未来的不确定性。若大于0,将做mcmc样本的全贝叶斯推理,如果为0,将做最大后验估计,默认值:0。
11、interval_width:衡量未来时间内趋势改变的程度。表示预测未来时使用的趋势间隔出现的频率和幅度与历史数据的相似度,值越大越相似,默认值:0.80。当mcmc_samples = 0时,该参数仅用于增长趋势模型的改变程度,当mcmc_samples > 0时,该参数也包括了季节性趋势改变的程度。
12、uncertainty_samples:用于估计未来时间的增长趋势间隔的仿真绘制数,默认值:1000。
13、yearly_seasonality: 数据是否有年季节性,默认“自动检测”。
14、weekly_seasonality: 数据是否有周季节性,默认“自动检测”。
15、daily_seasonality: 数据是否有天季节性,默认“自动检测”。
16、seasonality_mode: 季节性效应模式,默认加法模式“additive”,可选“multiplicative”乘法模式。
from prophet import Prophet
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
# 读取数据
df = pd.read_csv('./018/000001_Daily_2006_2017.csv')
# 选择日期和收盘价
df = df[['date','Close']]
数据: 我们只需要其中的日期和收盘价,即date和Close这两列。
# 注意:Prophet模型对于数据格式有要求,日期字段必须是datetime格式,这里通过pd.to_datetime来进行转换。
df['date'] = pd.to_datetime(df['date'])
# 这里需要将收盘价进行log处理,可以理解为归一化,注意最终绘图的时候需要将收盘价复原。
df['Close'] = np.log(df['Close'])
# 更改列名,更改为Prophet指定的列名ds和y
df = df.rename(columns={'date': 'ds', 'Close': 'y'})
# 划分数据,划分为训练集和验证集,将前十年的数据作为训练集,后一年的数据作为测试集。
df_train = df[:2699]
df_test = df[2699:]
现在的df如图所示:
观察数据:观察历史数据,看出来一点点趋势。
import plotly.express as px
fig = px.line(df_train, x="ds", y="y")
fig.show()
model = Prophet()
model.fit(df_train)
# make_future_dataframe: 作用是告诉模型我们要预测多长时间,以及时间的周期是什么。这里设置为365,即预测一年时间的数据。
#
future = model.make_future_dataframe(periods=365, freq='D')
# 进行预测,返回预测的结果forecast
forecast = model.predict(future)
# forecast['additive_terms'] = forecast['weekly'] + forecast['yearly'];
# 有:forecast['yhat'] = forecast['trend'] + forecast['additive_terms'] 。
# 因此:forecast['yhat'] = forecast['trend'] +forecast['weekly'] + forecast['yearly']。
# 如果有节假日因素,那么就会有forecast['yhat'] = forecast['trend'] +forecast['weekly'] + forecast['yearly'] + forecast['holidays']。
forecast
forecast表示:Dataframe中包含了很多预测结果的信息,其中yhat表示预测的结果。
# 对数据机型可视化操作,黑点表示真实数据,蓝线表示预测结果。蓝色区域表示一定置信程度下的预测上限和下限。
model.plot(forecast)
plt.show()
# 通过plot_componets()可以实现对数据的年、月、周不同时间周期下趋势性的可视化。
model.plot_components(forecast)
# 测试,把ds列,即data_series列设置为索引列
df_test = df_test.set_index('ds')
# 把预测到的数据取出ds列,预测值列yhat,同样把ds列设置为索引列。
forecast = forecast[['ds','yhat']].set_index('ds')
# 把数据转换回去,因为之前经过了log函数
df_test['y'] = np.exp(df_test['y'])
forecast['yhat'] = np.exp(forecast['yhat'])
# join:按照索引进行连接,
# dropna:能够找到DataFrame类型数据的空值(缺失值),将空值所在的行/列删除后,将新的DataFrame作为返回值返回。
df_all = forecast.join(df_test).dropna()
df_all.plot()
# 设置左上角小标
plt.legend(['true', 'yhat'])
plt.show()
对比图:
总结:没有加任何trick的长期预测效果很差,但是可以看的出来短期的预测准确率还可以。
import pandas as pd
from prophet import Prophet
import numpy as np
import math
import matplotlib.pyplot as plt
# 读取数据
df = pd.read_csv('./energy.csv')
# 更改列名,更改为Prophet指定的列名ds和y
dd = df.rename(columns={'Datetime':'ds','AEP_MW':'y'})
# 注意:Prophet模型对于数据格式有要求,日期字段必须是datetime格式,这里通过pd.to_datetime来进行转换。
dd['ds'] = pd.to_datetime(dd['ds'])
# 数据读取时为小时数据,我们需要将其聚合为天的数据
dd = dd.set_index('ds').resample('D').sum().reset_index()
dd
# 划分数据,划分为训练集和验证集,预测的数据设置为未来一个月
df_train = dd[:5025]
df_test = dd[5025:]
df_train.plot('ds', ['y'])
观察数据:导入一个好看的包,画的更漂亮一些
import plotly.express as px
fig = px.line(df_train, x="ds", y="y")
fig.show()
# 数据的变动会受到季节、周、天的影响,存在一定的规律性,因此我们将这三个参数设置为True
m = Prophet(yearly_seasonality=True, weekly_seasonality=True, daily_seasonality=True)
# 采用中国的假期模式,其余参数均保持默认
m.add_country_holidays(country_name="CN")
m.fit(df_train)
# make_future_dataframe: 作用是告诉模型我们要预测多长时间,以及时间的周期是什么。这里设置为30,即预测一个月时间的数据。
future = m.make_future_dataframe(periods=30, freq='D')
# 进行预测,返回预测的结果forecast
forecast = model.predict(future)
# forecast['additive_terms'] = forecast['weekly'] + forecast['yearly'];
# 有:forecast['yhat'] = forecast['trend'] + forecast['additive_terms'] 。
# 因此:forecast['yhat'] = forecast['trend'] +forecast['weekly'] + forecast['yearly']。
# 如果有节假日因素,那么就会有forecast['yhat'] = forecast['trend'] +forecast['weekly'] + forecast['yearly'] + forecast['holidays']。
forecast
forecast表示:Dataframe中包含了很多预测结果的信息,其中yhat表示预测的结果。
# 对数据机型可视化操作,黑点表示真实数据,蓝线表示预测结果。蓝色区域表示一定置信程度下的预测上限和下限。
m.plot(forecast)
plt.show()
# 通过plot_componets()可以实现对数据的年、月、周不同时间周期下趋势性的可视化。
m.plot_components(forecast);
# 测试
# 测试,把ds列,即data_series列设置为索引列
df_test = df_test.set_index('ds')
# 把预测到的数据取出ds列,预测值列yhat,同样把ds列设置为索引列。
forecast = forecast[['ds','yhat']].set_index('ds')
# df_test['y'] = np.exp(df_test['y'])
# forecast['yhat'] = np.exp(forecast['yhat'])
# join:按照索引进行连接,
# dropna:能够找到DataFrame类型数据的空值(缺失值),将空值所在的行/列删除后,将新的DataFrame作为返回值返回。
df_all = forecast.join(df_test).dropna()
df_all.plot()
# 设置左上角小标
plt.legend(['true', 'yhat'])
plt.show()
总结:相比于股票预测,只预测未来一个月的用电量,可以说很准确了,基本趋势都拟合到了。
模型评估:评估模型的准确程度,通过RMSE(均方误差)来度量y与pre之间的差异程度,值越小,说明拟合程度越好
train_len = len(df_train["y"])
rmse = np.sqrt(sum((df_train["y"] - forecast["yhat"].head(train_len)) ** 2) / train_len)
print('RMSE Error in forecasts = {}'.format(round(rmse, 2)))
模型存储:以上流程实现了Prophet模型搭建,但考虑到未来我们还要复用通过此历史数据训练的模型,因此我们要将模型存储到本地,并在需要的时候将其导入,使用pickle来保存模型
import pickle
# 模型保存
with open('../models_pickle/automl.pkl', 'wb') as f:
pickle.dump(model, f, pickle.HIGHEST_PROTOCOL)
# 模型读取
# with open('prophet_model.json', 'r') as md:
# model = model_from_json(json.load(md))
# 有的时候,由于双十一或者一些特殊节假日,我们可以设置某些天数是节假日,并且设置它的前后影响范围,也就是 lower_window 和 upper_window。
playoffs = pd.DataFrame({
'holiday': 'playoff',
'ds': pd.to_datetime(['2008-01-13', '2009-01-03', '2010-01-16',
'2010-01-24', '2010-02-07', '2011-01-08',
'2013-01-12', '2014-01-12', '2014-01-19',
'2014-02-02', '2015-01-11', '2016-01-17',
'2016-01-24', '2016-02-07']),
'lower_window': 0,
'upper_window': 1,
})
superbowls = pd.DataFrame({
'holiday': 'superbowl',
'ds': pd.to_datetime(['2010-02-07', '2014-02-02', '2016-02-07']),
'lower_window': 0,
'upper_window': 1,
})
holidays = pd.concat((playoffs, superbowls))
m = Prophet(holidays=holidays, holidays_prior_scale=10.0)
参考文章:
初识Prophet模型(一)-- 理论篇.
解读:一种来自Facebook团队的大规模时间序列预测算法(附github链接).
【python量化】将Facebook的Prophet算法用于股票价格预测.
独家 | 手把手教你用Python的Prophet库进行时间序列预测.
Facebook 时间序列预测算法 Prophet 的研究.
官网.
论文.
时间序列模型Prophet使用详细讲解.
怎么训练出一个NB的Prophet模型 .
NeuralProphet:基于神经网络的时间序列建模库 .
数据异常检测:
「经验」如何30min内排查出指标异动的原因.
「经验」指标异动排查中,3种快速定位异常维度的方法.
「经验」指标异动排查中,如何量化对大盘的贡献程度.
桥洞底下盖小被,小被里边抹眼泪,抹完眼泪无所谓,说什么啊我都对对对。