Forecasting at Scale
Abstract
预测是十分常见的数据科学任务,可用于企业的容量规划,目标设定,异常检测等。当时间序列多种多样并且缺少专家经验时,时间序列预测就变得尤其困难。本文提出了一种具有可解释参数的模块化回归模型。
Introduction
图1总结了用于大规模商业预测的"analyst-in-the-loop"方法。首先用具有参数可解释性的模型对时间序列进行建模[Modeling],然后对时序数据进行预测并用baseline的结果来衡量现有模型的预测效果[Forecast Evaluation]。当模型效果较差或者需要人工干预的时候,会进行人工干预[Surface Problems],接下来会检测预测结果并基于反馈调整模型[Visually Inspect Forecasts]。
Features of Business Time Series
图2展示了Facebook的Events(例如 create pages)对应的时间序列,显而易见的是时间序列数据有周期性的特征:以周或者年为周期,在圣诞节和新年有一个明显的下沉。这几种周期性的效果会自然的出现并且可以在人为产生的时间序列中被预测到。同时最后六个月的数据有一个明显的上升趋势,可能是因为新产品或者市场变化的影响。最后,这个数据也是有异常点的。下面图3展示了一些自动化的方法预测,其中有色曲线是对图2的时间序列数据进行预测,可以看出预测效果较差。
The Prophet Forecasting Model
接下来介绍prophet模型的具体算法细节,facebook给出了开源代码的github
,季节性项(周或月)
,节假日项
以及噪音项
,得到如下的加法模型,其中通常假设噪音项符合如下标准正态分布
The Trend Model
在Facebook真实场景应用中,共有两种趋势模型,一种是(2)式中的logistic growth model,这是一个非线性的模型
其中
表示最大渐近值,
的最大取值无限接近于
,
分别表示线性部分的斜率和偏置。当
时,
就是一个sigmoid函数。但是现实中往往
都是随时间变化的值,因此对于
,通过检测change point并在此基础上进行调整,得到式(3)的piecewise logistic growth model
其中假设在时刻
有
个变点,对应的变化率为
,其中向量
的每个分量定义如下
向量
的每个分量定义如下,通过分段函数在边界
处的值相等计算得到
另外一种是Linear Trend with Changepoints,本质上是一个分段的线性函数,(4)式所示
其中大部分参数与(3)一致,唯一不同的是
。Automatic Changepoint Selection
可以设置变点数量以及变点的变化率
,其中通常假设
的先验分布是拉普拉斯分布,即
,参数
可以控制变化率,当
趋向于0时,分段函数退化为完整的sigmoid函数或者线性函数。其中开源代码参数的调整在张戎另一篇文章
Trend Forecast Uncertainty
对于未来趋势点的预测,得到如下新的变化率
其中
,由历史的变点的变化率按照极大似然的思想得到。Seasonality
对于周期性项的拟合通过标准的傅立叶级数来近似,如下式(5)
其周期是
,需要估计的参数是
。文中对于年为周期的数据取
,对于周为周期的取
,如下分别得到
以及周期项如下
通常假设其中
的先验分布是正态分布
。Holidays and Events
根据不同的国家不同的节日,对于每一个节假日
,令
表示节假日的前后一段时间。得到如下的节假日项,
其中先验分布
。Model Fitting
接下来通过Stan进行函数拟合,得到
中参数的后验估计。其中可以预设
,change points以及节假日,三个先验分布的参数值。通过拟合训练得到
等参数值。对于图2的数据点,使用prophet拟合得到图5。Analyst-in-the-Loop Modeling
模型的很多参数可以通过专家经验给出。
Automating Evaluation of Forecasts
预测效果的自动评估机制略。
python的实现
import pandas as pd
from fbprophet import Prophet
df = pd.read_csv('./data/example_wp_log_peyton_manning.csv')
m = Prophet()
m.fit(df) # training model
future = m.make_future_dataframe(periods=365) # containing the dates for which a prediction is to be made
forecast = m.predict(future)
m.plot(forecast) # Fig1
fig2 = m.plot_components(forecast) # Fig2Fig1 真实值以及预测值的时序图Fig2 趋势项和周期项的拟合图像
import pandas as pd
from fbprophet import Prophet
df = pd.read_csv('./data/example_wp_log_peyton_manning.csv')
split = int(df.shape[0] / 2)
df_train = df.iloc[:split, :]# split datasets into train and test
m = Prophet()
m.fit(df_train) # training model
future = m.make_future_dataframe(periods=df.shape[0] - split)
forecast = m.predict(future)
fig = m.plot(forecast)
ax = fig.add_subplot(111)
ax.plot(df['ds'].astype('datetime64'), df['y'], 'k.')黑色的真实数据点落在预测区间内,预测值与真实值略有偏差
参考^Taylor S J, Letham B. Forecasting at scale[J]. The American Statistician, 2018, 72(1): 37-45.