接上…
Step 8. Facebook Prophet模型
在本人的博文 中我们简单介绍了Facebook的时序预测工具Prophet。最后,我们将采用这个工具对本问题进行建模预测,并比较一下Prophet和ARIMA系列模型的结果。
from fbprophet import Prophet
warnings.filterwarnings('ignore')
pd.set_option('display.width', None)
pd.set_option('display.max_rows', None)
简单回顾一下我们所关注的这个时序数据,
# Plot the entire time series diet and show gridlines
df_store_2_item_28_time.resample('M').sum().plot(grid=True,figsize=(20,5))
plt.show()
月度数据可看出季节性。
df_store_2_item_28_time.resample('A').sum().plot(grid=True,figsize=(20,5))
plt.show()
年度数据可看出趋势性。
decomposition = sm.tsa.seasonal_decompose(df_store_2_item_28_time.resample('M').sum(),
model = 'additive',
period=12)
fig = decomposition.plot()
plt.show()
从时序分解图中,我们看出的新特性是季节因素为加性看上去更为合适。(SARIMA是乘性模型)
Prophet需要输入的数据框的列名为ds,y;分别代表时间和观测值。
# rename date and sales, respectively ds and y
df_store_2_item_28.columns = ['ds','y']
df_store_2_item_28.head()
模型训练
缺省情况下,Prophet采用的就是加性模型。
m = Prophet(interval_width=0.95) #by default is 80%
model = m.fit(df_store_2_item_28)
预测
future = m.make_future_dataframe(periods=90)
forecast = m.predict(future)
forecast.head()
plot1 = m.plot(forecast)
深蓝色的线为预测值;黑色的点为实际值;浅蓝色的区域为95%的置信区间,由< forecast[‘yhat_lower’],forecast[‘yhat_upper’]>确定边界。
趋势拐点
实际数据中所发现的趋势很可能会有拐点,例如新品上市、无法预知的灾难等。Prophet会自动侦测这些观点并对模型进行相应调整。在这些拐点上,增长率的变化会使模型更加富有弹性,但也有可能会导致过拟合或者欠拟合。
Prophet的参数changepoint_prior_scale可以用来调整趋势的弹性,帮助克服过拟合和欠拟合。缺省情况下,Prophet是根据时序数据的前80%来推断拐点,你可以使用changepoint_range参数来改变这一点,你也可以使用changepoints参数来手动添加。下图中的点线表示了拐点。
from fbprophet.plot import add_changepoints_to_plot
plot1 = m.plot(forecast)
a = add_changepoints_to_plot(plot1.gca(),m,forecast)
成分图
plot2 = m.plot_components(forecast)
- 趋势成分:上升趋势明显
- 周季节性成分:周末购买量较多
- 年季节性成分:七月销量较高而一月销量较少。
Prophet提供参数Seasonality、Holidays Effects和Regressors来对节假日、周期和特殊事件进行建模,这些工具可以帮助改善模型。
模型评价
我们使用样本内数据来评价模型,评价指标使用MAE和MAPE。
df_merge = pd.merge(df_store_2_item_28, forecast[['ds','yhat_lower','yhat_upper','yhat']],on='ds')
df_merge = df_merge[['ds','yhat_lower','yhat_upper','yhat','y']]
df_merge.head()
# calculate MAE between observed and predicted values
y_true = df_merge['y'].values
y_pred = df_merge['yhat'].values
mae_01 = mean_absolute_error(y_true, y_pred)
print('MAE: %.3f' % mae_01)
MAE: 4.275
mape_01 = mean_absolute_percentage_error(y_true, y_pred)
print('MAPE: %.3f' % mape_01)
MAPE: 0.169
# plot expected vs actual
plt.plot(y_true, label='Actual')
plt.plot(y_pred, label='Predicted')
plt.legend()
plt.show()
从图上看,模型拟合效果不错。
未完待续…