Facebook prophet 简译
官网API
一、快速开始
Prophet 采取类似 sklearn 模式的 API,先创建一个Prophet的实例,然后调用它的 fit 和 predict 方法。
输入是一个DataFrame,必须包含这两列:ds 和 y。ds 必须是一个 date 或者 datetime。y 必须是数字,代表我们需要预测的序列的值。
类似:
index | ds | y |
---|---|---|
0 | 2000-01-01 | 1 |
1 | 2000-01-03 | 2 |
2 | 2000-01-04 | 3 |
二、饱和预测(Saturating Forecasts)
默认情况下,Prophet 使用线性模型来预测,当预测增长的时候,有时候会出现最大可达点,例如市场大小,总人口数等。这被称为承载能力,所以预测值应该在该点饱和。
Prophet 允许我们预测使用具有特定承载能力的逻辑增长趋势模型(logistic growth trend model)。使用该模型,必须指定特定的承载能力,必须在一个新的列上指明,该列需命名为:cap。
需要注意的是,cap 列的值不一定是常数,因为如果市场规模越来越大,那么上限可能也会越来越大。
饱和最小点(Saturating Minimum)
该模型也可以处理饱和最小点,需要指定一个新的列:floor,该列就代表饱和最小点。需要注意,若要使用饱和最小点,那么承载能力(最大容量)还是必须要指定。
三、趋势变化点(Trend Changepoints)
默认情况下,Prophet会自动的检测变化点(Changepoints)并且使得趋势(Trend)自动的去适应它。但是,如果你想手动控制这些过程,则可以使用多个输入参数。
Prophet 自动检测变化点(Automatic changepoint detection in Prophet)
Prophet 通过第一次指定大量的潜在变化点(potential changepoints)来检测变化点,然后在变化率改变之前提前稀疏(相当于L1正则化),变化率改变的地方有很多,但是 Prophet 会尽可能的减少使用。
默认情况下,Prophet 指定了25个潜在的变化点,这些变化点会统一放置在时间序列的前80%的地方,例如官网的图片:
默认潜在变化点的位置即使我们有很多变化率可能会改变的地方,由于进行了稀疏,所以大部分的变化点都未被使用。我们可以通过绘制每个变化点的变化率变化幅度来看到这一点:
潜在变化点的变化率可以通过参数 n_changepoints 来设置潜在变化点的数量,但是通过调整正则化可以更好的调整。
调整趋势的灵活性(Adjusting trend flexibility)
如果趋势的改变过拟合或者欠拟合(太灵活或者不够灵活),我们可以通过调整参数 changepoint_prior_scale 来调整之前的正则化强度。参数 changepoint_prior_scale 默认值是0.05,增加它可以加强正则化的强度,即趋势的改变会更加灵活。反之,趋势改变灵活性会降低。在默认值的基础上增加和减少该参数的值的效果图如下:
增加changepoint_prior_scale参数的值 减少changepoint_prior_scale参数的值指定变化点的位置(Specifying the locations of the changepoints)
如果你想手动设置变化点而不是使用自动检测变化点的位置,那么可以使用参数 changepoints 去指定潜在的变化点的位置。
四、季节性和假日效应(Seasonality And Holiday Effects)
指定季节性
如果时间序列超过两个周期,Prophet 会自动的设置每周和每年的季节性。它也将自动的为一个子日常时间系列设置日常季节性。也可以添加其他的季节性(如monthly,quarterly,hourly),通过使用 add_seasonality 方法。
该方法的输入参数是,名称(name),时期(period)以及季节性的傅立叶项数。增加傅里叶项的数量可以使季节性适应更快的变化周期,但是可能会过拟合。作为参考,默认情况下,Prophet 这样设置,每周季节性使用3项,年度季节性使用10项。例如:
m = Prophet(weekly_seasonality=False)
m.add_seasonality(name='monthly', period=30.5, fourier_order=5)
forecast = m.fit(df).predict(future)
m.plot_components(forecast)
为假期和特殊事件建模(Modeling Holidays and Special Events)
如果有假期或者其他想要建模的重复事件,则必须要为其创建数据框。数据框需要包含两列(holiday 和 ds)。它必须包含过去和未来(要预测的)的所有事件或者假期。如果未来没有该事件或者假期,那么预测的时候就不会包含其中。
可以包含列 lower_window 和 upper_window,可以拓展假期的范围,[lower_window,upper_window],例如 lower_window=-1,表示,昨天也是假期,upper_window=2 表示,明天和后天也是假期。还可以包含一列 prior_scale,表示每个假期以前的比例。(You can also include a column prior_scale to set the prior scale separately for each holiday, as described below.)
例如:
# Python
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))
表格一旦创建,就可以在创建类的时候通过节假日参数传入:
# Python
m = Prophet(holidays=holidays)
forecast = m.fit(df).predict(future)
假期效应可以在预测数据框中看到:
# Python
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][['ds', 'playoff', 'superbowl']][-10:]
DS | PLAYOFF | SUPERBOWL | |
---|---|---|---|
2190 | 2014-02-02 | 1.226679 | 1.192500 |
2191 | 2014-02-03 | 1.911294 | 1.373781 |
2532 | 2015-01-11 | 1.226679 | 0.000000 |
2533 | 2015-01-12 | 1.911294 | 0.000000 |
2901 | 2016-01-17 | 1.226679 | 0.000000 |
2902 | 2016-01-18 | 1.911294 | 0.000000 |
2908 | 2016-01-24 | 1.226679 | 0.000000 |
2909 | 2016-01-25 | 1.911294 | 0.000000 |
2922 | 2016-02-07 | 1.226679 | 1.192500 |
2923 | 2016-02-08 | 1.911294 | 1.373781 |
假日也会影响后一天的情况,我们发现在季后赛出场的时间里有一个高峰。
# Python
m.plot_components(forecast);
在 python 中使用 m.plot_forecast_component(forecast, 'superbowl') 只绘制 superbowl 假日的影响。
Prior scale for holidays and seasonality
如果假期过拟合,可以调整之前的参数 holidays_prior_scale。该参数默认是10,减小该参数会抑制假期效应,反之,会加强假期效应。类似的,有一个参数 seasonality_prior_scale 则对应于调整季节性模型的的影响。
通过在假期数据框中包括一列 previous_scale,可以为各个假期单独设置 prior scale。单个季节性的 prior scale 可以通过 add_seasonality 来设置。例如,为每周一次的季节性设置prior scale:(prior scale似乎可以理解为正则化强度)
# Python
m = Prophet()
m.add_seasonality(name='weekly', period=7, fourier_order=3, prior_scale=0.1)
Additional regressors
可以使用 add_regressor 方法为模型的线性部分添加额外的 regressors。在拟合和预测的数据中,会出现 regressor 列。例如,我们可以在NFL赛季期间的星期天添加额外的效果。在 components 图中,这个效应会显现:
# Python
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)
m.plot_components(forecast);
NLP 星期天也可以通过 “holiday” 的方式创建。add_regressor 方法为定义额外的线性 regressors 提供了更一般的接口,并且不需要 regressor 是一个 binary indicator。Another time series could be used as a regressor, although its future values would have to be known. The regressor cannot be constant in the training data; fitting will exit with an error if it is.
add_regressor 方法可以指定 prior scale (假期 prior scale 默认自动使用),无论 regressor 是否已经正则化。详细使用
help(Prophet.add_regressor) 查看。
五、不确定性区间(Uncertainty Intervals)
默认情况下,Prophet 会返回预测 yhat 的不确定性区间。这些不确定性间隔背后有几个重要的假设。预测存在不确定性的三个来源:趋势的不确定性,季节性估计的不确定性和额外的观测噪声。
趋势的不确定性
预测中最大的不确定性来自于未来趋势的变化。Prophet 能发现并且适应这些情况,但是我们期望未来是什么样的变化趋势呢?我们无法知晓,但是我们可以假设未来看到的情况和过去历史趋势变化一致。我们可以假设未来趋势变化的平均频率和幅度与我们在历史上观测到的相同。我们预测趋势的变化,就是通过计算他们的分布,然后来获得不确定性区间。
这种测量不确定性的方法之一就是通过增加参数 changepoint_prior_scale 来实现更好的灵活性,即增加预测的不确定性。这是因为我们对历史的变化率进行建模,如果希望未来更多变数,则增加该参数值。
不确定性区间宽度默认80%,可以使用参数 interval_width 来设置:
# Python
forecast = Prophet(interval_width=0.95).fit(df).predict(future)
季节的不确定性(Uncertainty in seasonality)
默认情况下,Prophet 只会返回趋势和观测噪声的不确定性。为了获得季节的不确定性,必须做完整的贝叶斯抽样(full Bayesian sampling),通过参数 mcmc.samples 来设置(该参数默认是0)。
# Python
m = Prophet(mcmc_samples=300)
forecast = m.fit(df).predict(future)
这取代了典型的 MAP 估计和 MCMC 采样,需要花费更长时间--think 10 minutes instead of 10 seconds。如果进行完整的抽样,当绘制它们时,会看到季节性分量的不确定性。
# Python
m.plot_components(forecast)
我们可以使用下面的方法来访问 Python 中的原始后验测试样本 m.predictive_samples(future)。
PyStan for Windows 中存在 upstream issues,使 MCMC 采样非常缓慢。 Windows 中 MCMC 采样的最佳选择是在 Linux VM 中使用 R 或 Python。
六、离群点(Outliers)
离群点影响 Prophet 预测的方式主要有两种,在这里,我们预测的维基百科对R页面的访问次数,但是有一段糟糕的数据:
# Python
df = pd.read_csv('../examples/example_wp_R_outliers1.csv')
df['y'] = np.log(df['y'])
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=1096)
forecast = m.predict(future)
m.plot(forecast);
预测的趋势似乎合理,但是不确定性区间太宽了。Prophet 可以处理历史的离群点,但是只是通过拟合趋势变化。不确定模型会以类似的幅度变化预计未来趋势。也就是不确定性区间太宽的原因。
处理异常值最好的方法就是删除它们 —— Prophet 处理缺失的数据没有问题。如果在历史中将它们的值设置为NA,但保留这些日期,那么Prophet将会预测它们的值。
# Python
df.loc[(df['ds'] > '2010-01-01') & (df['ds'] < '2011-01-01'), 'y'] = None
model = Prophet().fit(df)
model.plot(model.predict(future));
在上面的例子中,异常值扰乱了不确定性估计,但并未影响主要预测值。但是情况并非总是如此,例如在下面的例子中增加了异常值:
# Python
df = pd.read_csv('../examples/example_wp_R_outliers2.csv')
df['y'] = np.log(df['y'])
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=1096)
forecast = m.predict(future)
m.plot(forecast);
2015年6月,一组极端异常值混淆了季节性估计,它们使得未来的预测回荡。再一次强调,正确的方法是删除它们:
# Python
df.loc[(df['ds'] > '2015-06-01') & (df['ds'] < '2015-06-30'), 'y'] = None
m = Prophet().fit(df)
m.plot(m.predict(future));
非日常数据(Non-Daily Data)
分日数据(Sub-daily data)
Prophet 可以通过在 ds 列中传递带有时间戳的数据帧来预测时间序列与分日观察值(分日可以理解为 ‘日’ 以下的单位)。
当使用分日数据时,每日季节性将自动拟合。在这里我们使用 Prophet 以5分钟的分辨率拟合 Yosemite 每日温度:
# Python
df = pd.read_csv('../examples/example_yosemite_temps.csv')
m = Prophet(changepoint_prior_scale=0.01).fit(df)
future = m.make_future_dataframe(periods=300, freq='H')
fcst = m.predict(future)
m.plot(fcst);
每日季节性将显示在 components 图中:
# Python
m.plot_components(fcst);
每月数据(Monthly data)
可以使用 Prophet 来适应每月数据。但是,基础模型是连续时间的,这意味着如果将模型拟合到月度数据,然后询问每日预测,就会得到奇怪的结果。在这里我们预测未来10年的美国零售额:
# Python
df = pd.read_csv('../examples/example_retail_sales.csv')
m = Prophet().fit(df)
future = m.make_future_dataframe(periods=3652)
fcst = m.predict(future)
m.plot(fcst);
这里的预测看起来很嘈杂。发生的事情是这个特定的数据集只提供每月的数据。当我们拟合每年的季节性时,它只有每个月的第一个数据是比较好的,其余日子的季节性组分是不可识别的和过度拟合的(乱预测的)。当将Prophet应用于每月数据时,只能进行月度预测,可以通过将频率传递到 make_future_dataframe 来完成:
# Python
future = m.make_future_dataframe(periods=120, freq='M')
fcst = m.predict(future)
m.plot(fcst);
七、诊断 (Diagnostics)
先知有时间序列交叉验证的功能,它以使用历史数据来测量预测误差。这是通过选择历史记录中的截止点(cutoff points)来完成的,并且它们中的每一个都使用仅截至该截止点的数据拟合模型。然后我们可以将预测值与实际值进行比较。下图显示了 Peyton Manning 数据集的模拟历史预测,其中该模型适合5年的初始历史(initial history),然后预测一年的时间(horizon)。
Prophet 论文给出了模拟历史预测的进一步描述。
这种交叉验证程序可以使用 cross_validation 函数自动完成一系列历史截断。我们指定预测范围(horizon),然后指定初始训练周期的大小(initial)以及截止日期(period)之间的间隔。默认情况下,初始训练周期设置为 horizon 的三倍,并在每半个 horizon 进行截止。
cross_validation 的输出是在每个模拟预测日期,每个截止日期的真值 y 和样本外预测值 yhat 。然后可以计算 yha t对 y 的误差度量。
# Python
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(m, horizon = '730 days')
df_cv.head()
DS | YHAT | YHAT_LOWER | YHAT_UPPER | Y | CUTOFF | |
---|---|---|---|---|---|---|
0 | 2014-01-21 | 9.439510 | 8.799215 | 10.080240 | 10.542574 | 2014-01-20 |
1 | 2014-01-22 | 9.267086 | 8.645900 | 9.882225 | 10.004283 | 2014-01-20 |
2 | 2014-01-23 | 9.263447 | 8.628803 | 9.852847 | 9.732818 | 2014-01-20 |
3 | 2014-01-24 | 9.277452 | 8.693226 | 9.897891 | 9.866460 | 2014-01-20 |
4 | 2014-01-25 | 9.087565 | 8.447306 | 9.728898 | 9.370927 | 2014-01-20 |
八、How to Contribute
这个就不翻译了,详情戳 这里
九、翻译小结
本人英语战五渣,主要使用谷歌翻译,简单的翻译了一下,修改了一些不够通顺的地方,以供查阅之便。毕竟不是专业翻译人员,哪里有可以修改的地方,欢迎指正。