这篇是学习和使用笔记,参考内容比较多,没有很多原创,目的是希望大家快速入手这个包。
fbprophet这个包是facebook开源的时间序列预测包,因为其优良的性能,现在得到了大家的追捧,但是安装过程实在太多坑。
0.安装
本人使用mac电脑,因为这个包用到c++的环境,笔者是死活安装不成功,然后百度了好多问题无果,最终的解决方案是下面的安装步骤。
conda install pystan
#将安装很多依赖,不要用pip装,一定用conda装,嫌安装慢的,可以配置一个国内的镜像安装源。
#下载最新的prophet包,然后用
pip install fbprophet-0.6.tar.gz
期间如果遇到什么问题,欢迎随时私信我,这两步是最重要的。
1.入门
fbprophet完全继承了sklearn的模式,用fit,predict就可以进行使用。
fbprophet的输入是一个df,一般只包含两列第一列是日期,当然也可以是小时级别的,第二列就是具体的数据,这个包的好处显而易见,你不用去对数据特征进行处理了。
使用流程是:导包—导数据—建立一个prophet实例—fit—predict
import pandas as pd
from fbprophet import Prophet
sj = pd.read_excel('/Users/elliot/Desktop/manning.xlsx')
#sj.head(10)
m = Prophet()
m.fit(sj)#去训练
future = m.make_future_dataframe(periods=365)#再现有数据的基础上外推365天
future.tail()
pout = m.predict(future)#去预测
m.plot_components(pout)#画出分解图
2.饱和增长模型
饱和增长是指在资源有限的情况下事物的增长有上限的一种模式,符合大部分事物的发展规律,比如一个港口的吞吐量是不可能无限增长的,因为这个增长特征符合逻辑回归的曲线形式,因此又被成为logsitic模型,业内通常翻译为阻滞增长模型。
使用饱和增长模型,要在原有df的基础上新增一列cap,还要指定预测模型为logstic。
#前边导包导数据都一样的
sj['cap'] = 15.0
m = Prophet(growth='logistic')
m.fit(sj)
future = m.make_future_dataframe(periods=365)
future['cap'] = 15.0
future.tail()
pout = m.predict(future)
fig = m.plot(pout)
当然可以设置饱和增长的最大值,也可以设置饱和下降的最小值,看你业务需要,去调整变量名就好了。
3.突变点处理
当然了,时间序列不可能是完全平稳的,正常数据肯定存在突变点的,关于突变点检测有很多方法,网上基本都是现成的,比如用统计学的方法,用zscore,用孤立森林方法或者用其他方法。fbprophet可以自动识别突变点,这一点做得是比较好的。
这里我不想说的太复杂,简单说就是:同过changepoint和n_changepoint来指定异常点,如果啥也不给定,模型将从输入数据的前80%中找出25个异常点,怎么找呢,其实就是用了拐点检测的算法,具体不用搞懂。如果指定了就用你指定的日期作为异常点。
prophet对异常点的处理方法嘛很暴力就是忽略,相当于L1正则化,回想一下L1正则化就是将默写指标的权重设置为0来防止过拟合嘛。
from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(pout)
a = add_changepoints_to_plot(fig.gca(), m, pout)
图如下所示:
异常点自动检测
如果你不想从80%数据找异常点咋办,设置changepoint_range这个参数,设置为0.9。
如果你想调整预测结果的灵活性,你可以设置changepoint_prior_scale这个参数,默认是0.05,放大会使预测结果范围更加宽广。
m = Prophet(changepoint_prior_scale=0.5)
m.fit(sj)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
fig = m.plot(forecast)
调整changepoint_prior_scale参数结果
4.节假日效应
节假日是影响数据波动的一个重要因素,比如双十一可以显著提高销量,春节期间则能显著降低物流量等。所以需要对节假日进行一个特殊处理。
要想分析节假日效应的话需要新增加一个dataframe,包含节假期和日期两个字段,预测数据中也要注明节假期。当然如果节假日是一个区间,你可以再dataframe中新增两列,lower_window 和 upper_window,将节假日扩展为一个区间。
建好节假日的dataframe后,建模的时候传参进去就可以了,没啥好说的。
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)
m.fit(sj)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
fig = m.plot(forecast)
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][
['ds', 'playoff', 'superbowl']][-10:]
fig = m.plot_components(forecast)
from fbprophet.plot import plot_forecast_component
m.plot_forecast_component(forecast, 'superbowl')
#单独画出节假日影响的图像
如果发现节假日被过拟合了,你可以设置holidays_prior_scale参数来降低节假日的影响,这个参数默认取10,越大节假日影响越大,越小节假日影响越小。
5.季节性趋势
5.1 加法季节性
季节性使用傅里叶级数的方法进行建模的,这也是为什么fbprophet依赖C++包的原因。
在fbprophet中通过yearly_seasonality来调整,默认是10,如果季节性变化更明显,可以将这个数值调整的大一些,比如20。
你也可以通过指定weekly_seasonality和daily_seasonality两个参数来指定是否增加周和日的季节性。当然也可以通过add_seasality添加月、周、日甚至小时级别的季节性,三个参数,period、fourier_order,即傅里叶级数和prior_scale,先验规模,用来判断过拟合的。
m = Prophet(weekly_seasonality=False)
m.add_seasonality(name='monthly', period=30.5, fourier_order=5,prior_scale=0.1)
forecast = m.fit(sj).predict(future)
fig = m.plot_components(forecast)
同节假日相同,如果发现季节被过拟合了,可以设置 seasonality_prior_scale来调整。
5.2 乘法季节性
有些时候采用加法季节性是无效的,比如航空数据,有明显的随年度增加的趋势,但季节变化趋势也随着年份的增加发生了改变,采用传统的加法模型就不可行了。这时候可以尝试采用乘法季节性模型,就是在建模时候增加seasonality_mode='multiplicative'参数。值得注意的是因为设置了乘法模型,所以季节性和节假日都是乘法的关系。
m = Prophet(seasonality_mode='multiplicative')
m.fit(df)
forecast = m.predict(future)
fig = m.plot(forecast)
fig = m.plot_components(forecast)
当然了你也可以设置加法或者乘法,比如上述代码设置了季节性为乘法,那么你新增加一个季节性的时候可以指定是乘法或加法,这种做法就比较灵活。
m = Prophet(seasonality_mode='multiplicative')
m.add_seasonality('quarterly', period=91.25, fourier_order=8, mode='additive')
6.附加回归量
附加回归量是说有的因素可能影响预测结果,但是这个影响由没有展现出明显的年/月/日周期性,这时候可以加一个附加的回归量。用add_regressor这个方法,在建立预测模型之后添加,附加回归量取逻辑值。
def nfl_sunday(ds):
date = pd.to_datetime(ds)
if date.weekday() == 6 and (date.month > 8 or date.month < 2):
return 1
else:
return 0
df['nfl_sunday'] = df['ds'].apply(nfl_sunday)
m = Prophet()
m.add_regressor('nfl_sunday')
m.fit(df)
future['nfl_sunday'] = future['ds'].apply(nfl_sunday)
forecast = m.predict(future)
fig = m.plot_components(forecast)
7.预测区间
7.1 趋势不确定性
如果你打印fbprophet的预测结果,你会发现fbprophet是区间预测的。因为预测都是基于历史数据做出的,并且假设了未来数据和历史数据具有相似的变化趋势,这个假设可能会导致预测结果的不准确性。fbprophet提供了一个参数,interval_width,这个参数默认为0.8,越大则说明未来与历史变化趋势更接近。
m = Prophet(interval_width=0.95).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
7.2 季节不确定性
季节不确定性通过 mcmc.samples 参数调节,如果大于0做全贝叶斯估计,如果等于0做最大后验估计。谨慎使用啊,非常慢,cpu带不动。
m = Prophet(mcmc_samples=500).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
8.异常值
异常值不同于突变点,突变点那是正常波动造成的,异常点是数据有错误,或者统计口径发生了变化导致了数据的激增激降。异常值的存在将使得预测区间编的非常非常大。
处理异常值的最好办法就是删除这个数据,prophet依旧会根据趋势给出预测值,这感觉还不错,怎么删除呢,df赋值为none就好了,不用多说吧。
9.非日数据
有时候我们还需要预估小时级别的数据,这个prophet也是可以处理的,只要你传参是标准的时间戳格式就可以的,唯一要处理的就是外推数据,freq设置为‘H’。
当然月和年的数据是类似的,就是设置freq的问题,其他方法和天级别的预测相似的。
10.诊断
就是交叉验证,sklearn里也有交叉验证,用cross_validation进行。
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(m, initial='730 days', period='180 days', horizon = '365 days')
#参数意思是730天做阶段,每180天对365天的数据做一个交叉验证,
df_cv.head()
讲到这就基本讲完了,当然对内部机理的介绍还是比较少,我们只要会用就好了。
网友评论