关于prophet库的安装参考Windows平台下安装prophet,linux平台下一般没什么问题,直接用pip就可以。本文安装的fbprophet包版本为0.4.0(最新版本)
简介
输入到prophet中的数据要求是Dataframe类型,时间列的标签要命名为 ds ,数据列的标签需要命名为 y (命名一定要是ds,y否则无法通过编译)
引用模块
import pandas as pd
from fbprophet import Prophet
读取csv数据
df = pd.read_csv('Result.csv')
我们可以看到列名为ds和y,但是ds并不是datatime格式,需要进行转换,这里可以看到时间是每隔5分钟记录一次
df['ds']=pd.to_datetime(df['ds'], unit='s')
建立实例并拟合数据
学习(拟合)数据需要先创建一个Prophet类对象,同时可以通过参数来调整它的学习能力。然后再使用fit 函数来让它进行学习拟合。下面的代码是默认,无更改的Prophet模型。
m=Prophet()
m.fit(df)
生成时间框
我们需要给Prophet提供一个数据框,其中包含有ds,它是一个日期数据列,包含有历史数据的日期和预测的日期。
Prophet为我们提供了生成标准数据框的函数语句,Prophet.make_future_dataframe() ,参数periods设定了预测的天数。这里我设置了freq参数调整为分钟
future = m.make_future_dataframe(periods=5000,freq='min')
future.tail()
执行预测
Prophet提供的函数predict会产生一个新的数据框架,其中包含有*Prophet.make_future_dataframe()*生成的所有日期,以及它们对应的预测值,并命名标签为yhat,如果是历史日期,那么会给出模拟对历史数据的拟合值,可以通过它观察模型对历史数据的学习效果。此外返回的新数据框中还包含有预测值的上下界,如果设置了假期因素或者其他的额外因素,那么这些因素对预测的影响也会展示在该数据框中。
forecast = m.predict(future)
forecast.tail()
可视化
可以通过类中的plot函数绘制图像,给它输入predict函数返回的数据框架,就可以便捷地得到预测图。
查看更多细节
注:许多方法的细节可以通过help(Prophet)
或者 help(Prophet.fit)
来获得。
转折点自动检测
模型会在适应度允许的范围内寻找出大量的潜在转折点,可以通过以下代码显示出转折点的位置:
from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)
默认情况下,只有在时间序列的前80%才会推断出突变点,以便有足够的长度来预测未来的趋势,并避免在时间序列的末尾出现过度拟合的波动。这个默认值可以在很多情况下工作,但不是所有情况下都可以,可以使用changepoint_range参数进行更改。例如,Python中的m = Prophet(changepoint_range=0.9)。这意味着将在时间序列的前90%处寻找潜在的变化点
指定突变点的位置
如果你希望手动指定潜在突变点的位置而不是利用自动的突变点监测,可以使用 changepoints
参数。
m = Prophet(changepoints=['2014-01-01'])
m.fit(df)
调整趋势的灵活性
如果趋势的变化被过度拟合(即过于灵活)或者拟合不足(即灵活性不够),可以利用输入参数 changepoint_prior_scale
来调整稀疏先验的程度。默认下,这个参数被指定为 0.05 。
增加这个值,会导致趋势拟合得更加灵活。减少这个值,会导致趋势拟合得灵活性降低。
# 拟合模型
m = Prophet(changepoint_prior_scale=0.5)
m.fit(df)
对假期和特征事件建模
如果需要专门对节假日或者其它的事件进行建模,你就必须得为此创建一个新的dataframe,其中包含两列(节假日 holiday 和日期戳 ds ),每行分别记录了每个出现的节假日。这个数据框必须包含所有出现的节假日,不仅是历史数据集中还是待预测的时期中的。如果这些节假日并没有在待预测的时期中被注明, Prophet 也会利用历史数据对它们建模,但预测未来时却不会使用这些模型来预测。
注:也就是说,在待预测的日期里,我们也必须指定所有出现的节假日。
你可以在这个数据框基础上再新建两列 lower_window 和 upper_window ,从而将节假日的时间扩展成一个区间 [ lower_window , upper_window ] 。举例来说,如果想将平安夜也加入到 “圣诞节” 里,就设置 lower_window = -1 , upper_window = 0 ;如果想将黑色星期五加入到 “感恩节” 里,就设置 lower_window = 0 , upper_window = 1 。
下面我们创建一个数据框,其中包含了所有佩顿 · 曼宁参加过的决赛日期:
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))
上述代码中,我们将超级碗的日期既记录在了决赛的日期数据框中,也记录在了超级碗的日期数据框中。这就会造成超级碗日期的效应会在决赛日期的作用下叠加两次。
一旦这个数据框创建好了,就可以通过传入 holidays 参数使得在预测时考虑上节假日效应。这里我们仍以第一部分中佩顿 · 曼宁的数据为例:
df = pd.read_csv('examples/example_wp_log_peyton_manning.csv')
m = Prophet(holidays=holidays)
m.fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
可通过 forecast
数据框,来展示节假日效应:
# 看一下假期的最后10行数据
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][
['ds', 'playoff', 'superbowl']][-10:]
可以使用 plot_forecast_component
(从fbprophet.plot导入
)来画出独立的节假日的成分。类似如下代码:
from fbprophet.plot import plot_forecast_component
m.plot_forecast_component(forecast, 'superbowl')
季节性的傅里叶级数
季节性是用部分傅里叶和估计的。有关完整的细节,请参阅论文,以及维基百科上的这个图,以说明部分傅里叶和如何近似于一个线性周期信号。部分和(order)中的项数是一个参数,它决定了季节性的变化有多快。为了说明这一点, 我们仍似乎用第一部分中佩顿 · 曼宁的数据。每年季节性的默认傅立叶级数是10。默认值10通常是合适的,但是当季节性需要适应更高频率的变化时,它们可以增加,并且通常不那么平滑。在实例化模型时,可以为每个内置季节性指定傅立叶级数,这里增加到20:
from fbprophet.plot import plot_yearly
m = Prophet(yearly_seasonality=20).fit(df)
a = plot_yearly(m)
下图分别是10和20,可以看看差别
可以看到,曲线更加的多变了。增加傅立叶项的数量可以使季节性适应更快的变化周期,但也可能导致过度拟合:N个傅立叶项对应于用于建模周期的2N个变量。
对节假日和季节性设定先验规模
如果发现节假日效应被过度拟合了,通过设置参数 holidays_prior_scale
可以调整它们的先验规模来使之平滑,默认下该值取 10 。减少这个参数会降低假期效果:
m = Prophet(holidays=holidays, holidays_prior_scale=0.05).fit(df)
forecast = m.predict(future)
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][
['ds', 'playoff', 'superbowl']][-10:]
和之前相比,节假日效应的规模被减弱了,特别是对观测值较少的超级碗而言。类似的,还有一个 seasonality_prior_scale 参数可以用来调整模型对于季节性的拟合程度。
可以通过在节假日的dataframe中包含一个列prior_scale来单独设置先验规模。独立的季节性的先验规模可以作为add_seasonality的参数传递。例如,可以使用以下方法设置每周季节性的先验规模:
m = Prophet()
m.add_seasonality(
name='weekly', period=7, fourier_order=3, prior_scale=0.1)
异常值
Prophet 虽能够处理历史数据中的异常值,但仅仅是将它们与趋势的变化拟合在一起,认为未来也会有类似的趋势变化。
如上输出图所示,趋势预测看似合理,预测区间的估计却过于广泛。
处理异常值最好的方法是移除它们,而 Prophet 是能够处理缺失数据的。如果在历史数据中某行的值为空( NA
),但是在待预测日期数据框 future
中仍保留这个日期,那么 Prophet 依旧可以给出该行的预测值。
# 将2010年一年的数据设为缺失
df.loc[(df['ds'] > '2010-01-01') & (df['ds'] < '2011-01-01'), 'y'] = None
model = Prophet().fit(df)
model.plot(model.predict(future));
与机器学习算法的对比
与先进的机器学习算法如LGBM相比,Prophet作为一个时间序列的工具,优点就是不需要特征工程就可以得到趋势,季节因素和节假日因素,但是这同时也是它的缺点之一,它无法利用更多的信息,如在预测商品的销量时,无法利用商品的信息,门店的信息,促销的信息等。