這篇是學(xué)習(xí)和使用筆記,參考內(nèi)容比較多,沒有很多原創(chuàng),目的是希望大家快速入手這個包。
fbprophet這個包是facebook開源的時間序列預(yù)測包,因為其優(yōu)良的性能,現(xiàn)在得到了大家的追捧,但是安裝過程實在太多坑。
0.安裝
本人使用mac電腦,因為這個包用到c++的環(huán)境,筆者是死活安裝不成功,然后百度了好多問題無果,最終的解決方案是下面的安裝步驟。
conda install pystan
#將安裝很多依賴,不要用pip裝,一定用conda裝,嫌安裝慢的,可以配置一個國內(nèi)的鏡像安裝源。
#下載最新的prophet包,然后用
pip install fbprophet-0.6.tar.gz
期間如果遇到什么問題,歡迎隨時私信我,這兩步是最重要的。
1.入門
fbprophet完全繼承了sklearn的模式,用fit,predict就可以進行使用。
fbprophet的輸入是一個df,一般只包含兩列第一列是日期,當(dāng)然也可以是小時級別的,第二列就是具體的數(shù)據(jù),這個包的好處顯而易見,你不用去對數(shù)據(jù)特征進行處理了。
使用流程是:導(dǎo)包—導(dǎo)數(shù)據(jù)—建立一個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)#去訓(xùn)練
future = m.make_future_dataframe(periods=365)#再現(xiàn)有數(shù)據(jù)的基礎(chǔ)上外推365天
future.tail()
pout = m.predict(future)#去預(yù)測
m.plot_components(pout)#畫出分解圖
2.飽和增長模型
飽和增長是指在資源有限的情況下事物的增長有上限的一種模式,符合大部分事物的發(fā)展規(guī)律,比如一個港口的吞吐量是不可能無限增長的,因為這個增長特征符合邏輯回歸的曲線形式,因此又被成為logsitic模型,業(yè)內(nèi)通常翻譯為阻滯增長模型。
使用飽和增長模型,要在原有df的基礎(chǔ)上新增一列cap,還要指定預(yù)測模型為logstic。
#前邊導(dǎo)包導(dǎo)數(shù)據(jù)都一樣的
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)
當(dāng)然可以設(shè)置飽和增長的最大值,也可以設(shè)置飽和下降的最小值,看你業(yè)務(wù)需要,去調(diào)整變量名就好了。
3.突變點處理
當(dāng)然了,時間序列不可能是完全平穩(wěn)的,正常數(shù)據(jù)肯定存在突變點的,關(guān)于突變點檢測有很多方法,網(wǎng)上基本都是現(xiàn)成的,比如用統(tǒng)計學(xué)的方法,用zscore,用孤立森林方法或者用其他方法。fbprophet可以自動識別突變點,這一點做得是比較好的。
這里我不想說的太復(fù)雜,簡單說就是:同過changepoint和n_changepoint來指定異常點,如果啥也不給定,模型將從輸入數(shù)據(jù)的前80%中找出25個異常點,怎么找呢,其實就是用了拐點檢測的算法,具體不用搞懂。如果指定了就用你指定的日期作為異常點。
prophet對異常點的處理方法嘛很暴力就是忽略,相當(dāng)于L1正則化,回想一下L1正則化就是將默寫指標(biāo)的權(quán)重設(shè)置為0來防止過擬合嘛。
from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(pout)
a = add_changepoints_to_plot(fig.gca(), m, pout)
圖如下所示:

如果你不想從80%數(shù)據(jù)找異常點咋辦,設(shè)置changepoint_range這個參數(shù),設(shè)置為0.9。
如果你想調(diào)整預(yù)測結(jié)果的靈活性,你可以設(shè)置changepoint_prior_scale這個參數(shù),默認是0.05,放大會使預(yù)測結(jié)果范圍更加寬廣。
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)

4.節(jié)假日效應(yīng)
節(jié)假日是影響數(shù)據(jù)波動的一個重要因素,比如雙十一可以顯著提高銷量,春節(jié)期間則能顯著降低物流量等。所以需要對節(jié)假日進行一個特殊處理。
要想分析節(jié)假日效應(yīng)的話需要新增加一個dataframe,包含節(jié)假期和日期兩個字段,預(yù)測數(shù)據(jù)中也要注明節(jié)假期。當(dāng)然如果節(jié)假日是一個區(qū)間,你可以再dataframe中新增兩列,lower_window 和 upper_window,將節(jié)假日擴展為一個區(qū)間。
建好節(jié)假日的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')
#單獨畫出節(jié)假日影響的圖像
如果發(fā)現(xiàn)節(jié)假日被過擬合了,你可以設(shè)置holidays_prior_scale參數(shù)來降低節(jié)假日的影響,這個參數(shù)默認取10,越大節(jié)假日影響越大,越小節(jié)假日影響越小。
5.季節(jié)性趨勢
5.1 加法季節(jié)性
季節(jié)性使用傅里葉級數(shù)的方法進行建模的,這也是為什么fbprophet依賴C++包的原因。
在fbprophet中通過yearly_seasonality來調(diào)整,默認是10,如果季節(jié)性變化更明顯,可以將這個數(shù)值調(diào)整的大一些,比如20。
你也可以通過指定weekly_seasonality和daily_seasonality兩個參數(shù)來指定是否增加周和日的季節(jié)性。當(dāng)然也可以通過add_seasality添加月、周、日甚至小時級別的季節(jié)性,三個參數(shù),period、fourier_order,即傅里葉級數(shù)和prior_scale,先驗規(guī)模,用來判斷過擬合的。
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)
同節(jié)假日相同,如果發(fā)現(xiàn)季節(jié)被過擬合了,可以設(shè)置 seasonality_prior_scale來調(diào)整。
5.2 乘法季節(jié)性
有些時候采用加法季節(jié)性是無效的,比如航空數(shù)據(jù),有明顯的隨年度增加的趨勢,但季節(jié)變化趨勢也隨著年份的增加發(fā)生了改變,采用傳統(tǒng)的加法模型就不可行了。這時候可以嘗試采用乘法季節(jié)性模型,就是在建模時候增加seasonality_mode='multiplicative'參數(shù)。值得注意的是因為設(shè)置了乘法模型,所以季節(jié)性和節(jié)假日都是乘法的關(guān)系。
m = Prophet(seasonality_mode='multiplicative')
m.fit(df)
forecast = m.predict(future)
fig = m.plot(forecast)
fig = m.plot_components(forecast)
當(dāng)然了你也可以設(shè)置加法或者乘法,比如上述代碼設(shè)置了季節(jié)性為乘法,那么你新增加一個季節(jié)性的時候可以指定是乘法或加法,這種做法就比較靈活。
m = Prophet(seasonality_mode='multiplicative')
m.add_seasonality('quarterly', period=91.25, fourier_order=8, mode='additive')
6.附加回歸量
附加回歸量是說有的因素可能影響預(yù)測結(jié)果,但是這個影響由沒有展現(xiàn)出明顯的年/月/日周期性,這時候可以加一個附加的回歸量。用add_regressor這個方法,在建立預(yù)測模型之后添加,附加回歸量取邏輯值。
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.預(yù)測區(qū)間
7.1 趨勢不確定性
如果你打印fbprophet的預(yù)測結(jié)果,你會發(fā)現(xiàn)fbprophet是區(qū)間預(yù)測的。因為預(yù)測都是基于歷史數(shù)據(jù)做出的,并且假設(shè)了未來數(shù)據(jù)和歷史數(shù)據(jù)具有相似的變化趨勢,這個假設(shè)可能會導(dǎo)致預(yù)測結(jié)果的不準(zhǔn)確性。fbprophet提供了一個參數(shù),interval_width,這個參數(shù)默認為0.8,越大則說明未來與歷史變化趨勢更接近。
m = Prophet(interval_width=0.95).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
7.2 季節(jié)不確定性
季節(jié)不確定性通過 mcmc.samples 參數(shù)調(diào)節(jié),如果大于0做全貝葉斯估計,如果等于0做最大后驗估計。謹慎使用啊,非常慢,cpu帶不動。
m = Prophet(mcmc_samples=500).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
8.異常值
異常值不同于突變點,突變點那是正常波動造成的,異常點是數(shù)據(jù)有錯誤,或者統(tǒng)計口徑發(fā)生了變化導(dǎo)致了數(shù)據(jù)的激增激降。異常值的存在將使得預(yù)測區(qū)間編的非常非常大。
處理異常值的最好辦法就是刪除這個數(shù)據(jù),prophet依舊會根據(jù)趨勢給出預(yù)測值,這感覺還不錯,怎么刪除呢,df賦值為none就好了,不用多說吧。
9.非日數(shù)據(jù)
有時候我們還需要預(yù)估小時級別的數(shù)據(jù),這個prophet也是可以處理的,只要你傳參是標(biāo)準(zhǔn)的時間戳格式就可以的,唯一要處理的就是外推數(shù)據(jù),freq設(shè)置為‘H’。
當(dāng)然月和年的數(shù)據(jù)是類似的,就是設(shè)置freq的問題,其他方法和天級別的預(yù)測相似的。
10.診斷
就是交叉驗證,sklearn里也有交叉驗證,用cross_validation進行。
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(m, initial='730 days', period='180 days', horizon = '365 days')
#參數(shù)意思是730天做階段,每180天對365天的數(shù)據(jù)做一個交叉驗證,
df_cv.head()
講到這就基本講完了,當(dāng)然對內(nèi)部機理的介紹還是比較少,我們只要會用就好了。