R+python︱Facebook大規模時序預測『真』神器——Prophet(遍地代碼圖)

經統專業看到預測的packages都是很眼饞的。除了之前的forecast包,現在這個prophet功能也很強大。本packages是由機器之心報道之後,抽空在週末試玩幾小時。一些基本介紹可見機器之心的《業界
|
Facebook開源大規模預測工具Prophet:支持Python和R》

並不喜歡理論分析,能直接上案例的,一般不碼字,力求簡單粗暴!!

官網網址:https://facebookincubator.github.io/prophet/
github網址:https://github.com/facebookincubator/prophet
論文:《Forecasting at Scale Sean J.Taylor and Benjamin Letham》
案例數據下載:http://download.csdn.net/detail/sinat_26917383/9764537

最後會補充一些facebook的理論。


那麼試玩下來覺得比較讚的功能點:

  • 1、大規模、細粒度數據。其實並不是大量數據,而是時間粒度可以很小,在學校玩的計量大多都是“年/月”粒度,而這個包可以適應“日/時”級別的,具體的見後面的案例就知道了。不過,預測速度嘛~
    可以定義爲:較慢!!!
  • 2、趨勢預測+趨勢分解,最亮眼模塊喲~~
    擬合的有兩種趨勢:線性趨勢、logistic趨勢;趨勢分解有很多種:Trend趨勢、星期、年度、季節、節假日,同時也可以看到節中、節後效應。
  • 3、突變點識別+調整。多種對抗突變辦法以及調節方式。
  • 4、異常值/離羣值檢測。時間維度的異常值檢測。突變點和異常點既相似、又不同。
  • 5、處理缺失值數據。這裏指的是你可能有一些時間片段數據的缺失,之前的做法是先插值,然後進行預測(一些模型不允許斷點),這裏可以兼顧缺失值,同時也達到預測的目的。可以處理缺失值數據,這點很棒。

prophet應該就是我一直在找的,目前看到最好的營銷活動分析的預測工具,是網站分析、廣告活動分析的福音,如果您看到本篇文章內的方法,您在使用中發現什麼心得,還請您儘量分享出來~

 # install.packages('prophet')
library(prophet)
library(dplyr)

.
.


一、趨勢預測+趨勢分解

1、案例一:線性趨勢+趨勢分解

  • 數據生成+建模階段
history <- data.frame(ds = seq(as.Date('2015-01-01'), as.Date('2016-01-01'), by = 'd'),
                      y = sin(1:366/200) + rnorm(366)/10)

m <- prophet(history,growth = "linear")

其中,生成數據的時候注意,最好用ds(時間項)、y(一定要numeric)這兩個命名你的變量,本案例是單序列+時間項。數據長這樣:
這裏寫圖片描述
prophet是生成模型階段,m中有很多參數,有待後來人慢慢研究。

  • 預測階段
#時間函數
future <- make_future_dataframe(m, periods = 365)
tail(future)
#預測
forecast <- predict(m, future)
tail(forecast[c('ds', 'yhat', 'yhat_lower', 'yhat_upper')])
#直線預測
plot(m, forecast)
#趨勢分解
prophet_plot_components(m, forecast)

make_future_dataframe:有趣的時間生成函數,之前的ds數據是2015-1-1到2016-1-1,現在生成了一個2015-1-1到2016-12-30序列,多增加了一年,以備預測。而且可以靈活的調控是預測天,還是周,freq參數。
predict,預測那麼ds是時間,yhat是預測值,lower和upper是置信區間。
感受一下plot:
這裏寫圖片描述
prophet_plot_components函數是趨勢分解函數,將趨勢分成了趨勢項、星期、年份,這是默認配置。
這裏寫圖片描述

.

2、案例二:logitics趨勢+趨勢分解

logitics是啥? 不懂煩請百度。

#數據生成階段
history <- data.frame(ds = seq(as.Date('2015-01-01'), as.Date('2016-01-01'), by = 'd'),
                      y = sin(1:366/200) + rnorm(366)/10,
                      cap=sin(1:366/200) + rnorm(366)/10+rep(0.3,366))
#最大增長趨勢,cap設置cap,就是這個規模的頂點,y當時頂點

#模型生成
m <- prophet(history,growth = "logistic")
future <- make_future_dataframe(m, periods = 1826)
future$cap <- sin(1:2192/200) + rnorm(2192)/10+rep(0.3,2192)

#預測階段
fcst <- predict(m, future)
plot(m, fcst)

prophet這裏如果是要擬合logitics趨勢,就需要一個cap變量,這個變量是y變量的上限(譬如最大市場規模),因爲y如果服從logitics趨勢不給範圍的話,很容易一下預測就到頂點了,所以cap來讓預測變得不那麼“脆弱”…
下面來看一個失敗擬合logitics案例:
這裏寫圖片描述

.
.


二、節假日效應

可以考察節中、節後效應。來看看paper中如何解釋節日效應的(論文地址):
這裏寫圖片描述

也就是說,節日效應能量函數h(t)由兩部分組成,Z(t)是一個示性函數的集合(indicator function),而參數K服從(0,v)正態分佈。可以說,將節日看成是一個正態分佈,把活動期間當做波峯,lower_window 以及upper_window 的窗口作爲擴散。

1、節中效應

#數據生成:常規數據
history <- data.frame(ds = seq(as.Date('2015-01-01'), as.Date('2016-01-01'), by = 'd'),
                      y = sin(1:366/200) + rnorm(366)/10,
                      cap=sin(1:366/200) + rnorm(366)/10+rep(0.3,366))
#數據生成:節假日數據
library(dplyr)
playoffs <- data_frame(
  holiday = 'playoff',
  ds = as.Date(c('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 <- data_frame(
  holiday = 'superbowl',
  ds = as.Date(c('2010-02-07', '2014-02-02', '2016-02-07')),
  lower_window = 0,
  upper_window = 1
)
holidays <- bind_rows(playoffs, superbowls)

#預測
m <- prophet(history, holidays = holidays)
forecast <- predict(m, future)

#影響效應
forecast %>% 
  select(ds, playoff, superbowl) %>% 
  filter(abs(playoff + superbowl) > 0) %>%
  tail(10)

#趨勢組件
prophet_plot_components(m, forecast);

數據生成環節有兩個數據集要生成,一批數據是常規的數據(譬如流量),還有一個是節假日的時間數據
其中lower_window,upper_window 可以理解爲假日延長時限,國慶和元旦肯定休息時間不一致,設置地很人性化,譬如聖誕節的平安夜+聖誕節兩天,那麼就要設置(lower_window = -1, upper_window = 1)。這個lower_window 的尺度爲天,所以如果你的數據是星期/季度,需要設置-7/+7,比較合理。舉一個python中的設置方式(時序是by week):

c3_4 = pd.DataFrame({
  'holiday': 'c1',
  'ds': pd.to_datetime(['2017/2/26',
'2017/3/5'),
  'lower_window': -7,
  'upper_window': 7,
})

lower_window,upper_window 是節日效應的精髓,一般情況下,在-7 / +7 的時間跟活動期的數值不一樣,剛好可以很多表示出節日的正態效應。
數據長這樣:

     holiday         ds lower_window upper_window
       <chr>     <date>        <dbl>        <dbl>
1    playoff 2008-01-13            0            1
2    playoff 2009-01-03            0            1
3    playoff 2010-01-16            0            1
4    playoff 2010-01-24            0            1
5    playoff 2010-02-07            0            1

預測階段,記得要開啓prophet(history, holidays = holidays)中的holidays。現在可以來看看節假日效應:

          ds      playoff superbowl
1 2015-01-11  0.012300004         0
2 2015-01-12 -0.008805914         0
3 2016-01-17  0.012300004         0
4 2016-01-18 -0.008805914         0
5 2016-01-24  0.012300004         0
6 2016-01-25 -0.008805914         0
7 2016-02-07  0.012300004         0
8 2016-02-08 -0.008805914         0

從數據來看,可以看到有一個日期是重疊的,超級碗+季後賽在同一天,那麼這樣就會出現節日效應累加的情況。
可以看到季後賽當日的影響比較明顯,超級碗當日基本沒啥影響,當然了,這些數據都是我瞎編的,要是有效應就見xxx。
趨勢分解這裏,除了趨勢項、星期、年份,多了一個節假日影響,看到了嗎?

這裏寫圖片描述

.

2、調和節日效應(Prior scale for holidays and seasonality)

一些情況下節假日會發生過擬合,那麼可以使用holidays.prior.scale參數來進行調節,使其平滑過渡。(不知道翻譯地對不對,本來剛開始以爲是節後效應…)

#節後效應 holidays.prior.scale
m <- prophet(history, holidays = holidays, holidays.prior.scale = 1)
forecast <- predict(m, future)
forecast %>% 
  select(ds, playoff, superbowl) %>% 
  filter(abs(playoff + superbowl) > 0) %>%
  tail(10)

主要通過holidays.prior.scale來實現,默認是10。由於筆者亂整數據,這裏顯示出效應,所以粘貼官網數據。官網的案例裏面,通過調節,使得當晚超級碗的效應減弱,兼顧了節前的情況對當日的影響。
同時除了節前,還有季節前的效應,通過參數seasonality_prior_scale 調整

    DS  PLAYOFF SUPERBOWL
2190    2014-02-02  1.362312    0.693425
2191    2014-02-03  2.033471    0.542254
2532    2015-01-11  1.362312    0.000000
2533    2015-01-12  2.033471    0.000000
2901    2016-01-17  1.362312    0.000000
2902    2016-01-18  2.033471    0.000000
2908    2016-01-24  1.362312    0.000000

.
.


三、突變點調節、間斷點、異常點

本節之後主要就是玩案例裏面的數據,案例數據如果R包中沒有,可以從這裏下載

.

1、Prophet——自動突變點識別

時間序列裏面的很可能存在突變點,譬如一些節假日的衝擊。Prophet會自動檢測這些突變點,並進行適當的調整,但是機器判斷會出現:沒有對突變點進行調整、突變點過度調整兩種情況,如果真的突變點出現,也可以通過函數中的參數進行調節。

Prophet自己會檢測一些突變點,以下的圖就是Prophet自己檢測出來的,虛縱向代表突變點。檢測到了25個,那麼Prophet的做法跟L1正則一樣,“假裝”/刪掉看不見這些突變。
這裏寫圖片描述
其自己檢驗突變點的方式,類似觀察ARIMA的自相關/偏相關係數截尾、拖尾:
這裏寫圖片描述
.

2、人爲干預突變點——彈性範圍

通過changepoint_prior_scale進行人爲干預。

df = pd.read_csv('../examples/example_wp_peyton_manning.csv')
m <- prophet(df, changepoint.prior.scale = 0.5)
forecast <- predict(m, future)
plot(m, forecast)

來感受一下changepoint.prior.scale=0.05和0.5的區別:
這裏寫圖片描述
這裏寫圖片描述
可以把changepoint.prior.scale看成一個彈性尺度,值越大,受異常值影響越大,那麼波動越大,如0.5這樣的。
.

3、人爲干預突變點——某突變點

當你知道數據中,存在某一個確定的突變點,且知道時間。可以用changepoints 函數。不po圖了。

df = pd.read_csv('../examples/example_wp_peyton_manning.csv')
m <- prophet(df, changepoints = c(as.Date('2014-01-01')))
forecast <- predict(m, future)
plot(m, forecast)

.

4、突變預測

標題取了這麼一個名字,也是夠嚇人的,哈哈~ 第三節的前3點都是如何消除突變點並進行預測。
但是! 現實是,突變點是真實存在,且有些是有意義的,譬如雙11、雙12這樣的節日。不能去掉這些突變點,但是不去掉又會影響真實預測,這時候Prophet新奇的來了一招:序列生成模型中,多少受異常值些影響(類似前面的changepoint_prior_scale,但是這裏是從生成模型階段就給一個彈性值)。
這裏從生成模型中可以進行三個角度的調節:
(1)調節趨勢;
(2)季節性調節

  • (1)趨勢突變適應
df = pd.read_csv('../examples/example_wp_peyton_manning.csv')
m <- prophet(df, interval.width = 0.95)
forecast <- predict(m, future)

在prophet生成模型階段,加入interval.width,就是代表生成模型時,整個序列趨勢,還有5%受異常值影響。

  • (2)季節性突變適應

對於生產廠家來說,季節性波動是肯定有的,那麼又想保留季節性突變情況,又要預測。而且季節性適應又是一個比較麻煩的事情,prophet裏面需要先進行全貝葉斯抽樣,mcmc.samples參數,默認爲0.

m <- prophet(df, mcmc.samples = 500)
forecast <- predict(m, future)
prophet_plot_components(m, forecast);

打開mcmc.samples按鈕,會把MAP估計改變爲MCMC採樣,訓練時間很長,可能是之前的10倍。最終結果,官網DAO圖:
這裏寫圖片描述

.

5、異常值/離羣值

異常值與突變點是有區別的,離羣值對預測影響尤其大。

df <- read.csv('../examples/example_wp_R_outliers1.csv')
df$y <- log(df$y)
m <- prophet(df)
future <- make_future_dataframe(m, periods = 1096)
forecast <- predict(m, future)
plot(m, forecast);

這裏寫圖片描述

對結果的影響很大,而且導致預測置信區間擴大多倍不止。prophet的優勢體現出來了,prophet是可以接受空缺值NA的,所以這些異常點刪掉或者NA掉,都是可以的。

#異常點變爲NA+進行預測
outliers <- (as.Date(df$ds) > as.Date('2010-01-01')
             & as.Date(df$ds) < as.Date('2011-01-01'))
df$y[outliers] = NA
m <- prophet(df)
forecast <- predict(m, future)
plot(m, forecast);

當然啦,你也可以刪掉整一段影響數據,特別是天災人禍的影響是永久存在的,那麼可以刪掉這一整段。下圖就是這樣的情況,2015年6月份左右的一批數據,都是離羣值。
這裏寫圖片描述

.
.


四、缺失值、空缺時間的處理+預測

前面第三章後面就提過,prophet是可以處理缺失值。那麼這裏就可以實現這麼一個操作,如果你的數據不完整,且是間斷的,譬如你有一個月20天的數據,那麼你也可以根據prophet預測,同時給予你每天的數據結果。實現了以下的功能:

prophet=缺失值預測+插值
df <- read.csv('../examples/example_retail_sales.csv')
m <- prophet(df)
future <- make_future_dataframe(m, periods = 3652)
fcst <- predict(m, future)
plot(m, fcst);

這裏寫圖片描述

源數據長這樣:

            ds      y
1   1992-01-01 146376
2   1992-02-01 147079
3   1992-03-01 159336
4   1992-04-01 163669
5   1992-05-01 170068

也就是你只有一年的每個月的數據,上面是預測接下來每一天的數據,也能預測,但是後面每天預測的誤差有點大。所以你可以設置make_future_dataframe中的freq,後面預測的是每個月的:

future <- make_future_dataframe(m, periods = 120, freq = 'm')
fcst <- predict(m, future)
plot(m, fcst)

這裏寫圖片描述
.


五、用python實現prophet時序預測

1、安裝

筆者在linux實踐的時候,安裝就遇到了很多問題。

pip install fbprophet

官網說:Make sure compilers (gcc, g++) and Python development tools (python-dev) are installed. If you are using a VM, be aware that you will need at least 2GB of memory to run PyStan.
還需要預先加載pystan這個包。
同時在調用的時候,from fbprophet import Prophet 報錯,因爲github最新版不是官方文檔中的語句了。。。真是坑
應該是:from forecaster import Prophet

.

2、實踐案例

模擬一個最簡單的節日效應的案例:

from forecaster import Prophet
m = Prophet(holidays=holidays, holidays_prior_scale=20)
m.fit(df)
future = m.make_future_dataframe(periods = 1 ,freq = 'w' )
forecast = m.predict(future)
forecast

forecast中包含所有的信息,是一個dataframe表。包含:預測的y,趨勢項、季節項、活動項等
其中freq 可以自己調節。其中plot_components是趨勢分解。

m.plot_components(forecast)

這裏寫圖片描述


延伸一:Facebook 的數據預測工具 Prophet ——貝葉斯推理

Facebook 的數據預測工具 Prophet 有何優勢?用貝葉斯推理一探究竟

Prophet 在進行預測,其後端系統是一個概率程序語言 Stan,這代表 Prophet 能發揮出很多貝葉斯算法的優勢,比如說:

使模型具有簡單、易解釋的週期性結構;
預測結果包括才完全後驗分佈中導出的置信區間,即Prophet提供的是一個數據驅動的風險估計。
在下面研究中,研究者讓Prophet對兩組數據進行預測,在後端使用概率程序語言,讀者可以藉此看到使用Stan的一些工作細節。

Prophet使用了一種通用時間序列模型,這種模型可適用於Facebook上的數據,並且具有分段走向(piecewise trends)、多週期及彈性假期(floating holiday)三種特性。

Prophet的把時間序列預測問題轉變成了一個曲線擬合練習(exercise)。在這個曲線中,因變量是增長、週期和holiday的總體表現。


 - 增長(growth)

這一部分採用一個隨時間變化的邏輯增長模型,屬於非線性增長,所以,要用簡單的分段常數函數來模擬線性增長。
用比率調整向量模擬分段點,每個分段點都對應一個具體的時間點。用拉普拉斯分佈(Laplace distribution)模擬比率調整變量,位置參數(location parameter)設定爲0。

 - Prophet 模型週期(periodic seasonality)

採用標準傅里葉級數。年、周的週期性(seasonality)近似值分別爲20和6,週期性成分(seasonal component)在正常情況下是平滑狀態。

 - 假期(Holiday
用一個指標函數來模擬。
使用者可以調節擴散參數(spread parameter),以模擬未來會有多少歷史季節性變化(historical seasonal variation)。

公衆號“素質雲筆記”定期更新博客內容:

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章