更多原創(chuàng)AI內(nèi)容,請(qǐng)關(guān)注 公眾號(hào) MyEncyclopedia
NeuralProphet深度學(xué)習(xí)版Prophet
NeuralProphet
負(fù)有盛名俭厚,是 Facebook開發(fā)的新一代 Prophet 時(shí)間序列預(yù)測(cè)框架司倚,堪稱時(shí)間序列預(yù)測(cè)神器。但是它的API使用,調(diào)參寝殴,原理不太為大家所知蒿叠,我們會(huì)花幾期文章和視頻,我們將由淺入深杯矩,由實(shí)踐至原理栈虚,揭開其神秘面紗。
NeuralProphet
繼承了 Prophet 模塊可接受性的特點(diǎn)史隆,將預(yù)測(cè)的值分解到趨勢(shì)魂务、季節(jié)性、AR泌射、事件(節(jié)日)幾個(gè)模塊粘姜。其中 AR 部分的神經(jīng)網(wǎng)絡(luò)實(shí)現(xiàn)由 <u>AR-Net: A simple Auto-Regressive Neural Network for time-series</u> 這篇論文詳細(xì)描述。此外熔酷,NeuralProphet 整體用 PyTorch 重新實(shí)現(xiàn)孤紧,主要特性如下
- 使用 PyTorch 的優(yōu)化,性能比原始 Prophet 快不少
- 引入 AR-Net 建模時(shí)間序列自回歸拒秘,并配有非線性層
- 自定義損失和指標(biāo)
- 滯后協(xié)變量(lagged covariates) 和 AR 本地上下文特性 (local context)
盡管 NeuralProphet
有不少優(yōu)勢(shì)号显,但是使用起來小問題不斷,主要表現(xiàn)為文檔不甚詳細(xì)躺酒,API 設(shè)計(jì)的比較智能(隱晦)押蚤,坑不少。這一期我們來實(shí)戰(zhàn)體驗(yàn)一下羹应,后續(xù)會(huì)深入代碼和論文揽碘。
<u>相關(guān)論文鏈接:</u>
[Prophet] Forecasting at scale https://peerj.com/preprints/3190/
NeuralProphet: Explainable Forecasting at Scale https://arxiv.org/abs/2111.15397
AR-Net: A simple Auto-Regressive Neural Network for time-series https://arxiv.org/abs/1911.12436
安裝NeuralProphet
使用命令通過 pip 就可以安裝 NeuralProphet。
pip install neuralprophet==0.5.0
如果在 Jupyter Notebook 中使用 NeuralProphet园匹,最好安裝實(shí)時(shí)版本雳刺,允許你實(shí)時(shí)可視化模型損失。
pip install neuralprophet[live]==0.5.0
要注意一點(diǎn)裸违,安裝 neuralprophet 會(huì)關(guān)聯(lián)安裝 Pytorch CPU版本庫掖桦,如果你需要使用 GPU 或者不希望覆蓋原有的 Pytorch 版本,請(qǐng)手動(dòng)安裝供汛。
此外滞详,MyEncyclopedia 和往常一樣,為大家準(zhǔn)備了一個(gè) docker 鏡像紊馏,預(yù)裝最新的 NeuralProphet 庫料饥,鏡像中還包含預(yù)下載的數(shù)據(jù)集和本文所有的 Jupyter Notebook 代碼。大家關(guān)注 MyEncyclopedia公眾號(hào)朱监,執(zhí)行下面命令后網(wǎng)頁打開 http://localhost:8888/ 開箱即用
docker pull myencyclopedia/neuralprophet-tut
docker run -p 8888:8888 myencyclopedia/neuralprophet-tut bash -c 'jupyter notebook --port 8888 --NotebookApp.token='' --NotebookApp.password='' --ip 0.0.0.0 --allow-root'
標(biāo)準(zhǔn)普爾 500 指數(shù)數(shù)據(jù)集
這次實(shí)戰(zhàn)我們使用過去 10 年標(biāo)準(zhǔn)普爾 500 指數(shù)的每日股價(jià)數(shù)據(jù)岸啡。可以通過如下命令下載數(shù)據(jù)集赫编,使用 docker 鏡像的同學(xué)無需額外下載巡蘸。
import pandas_datareader as pdr
from datetime import datetime
import matplotlib.pyplot as plt
%matplotlib inlinestart = datetime(2010, 12, 13)
end = datetime(2020, 12, 11)
df_sp500 = pdr.get_data_fred('sp500', start, end)
plt.figure(figsize=(10, 7))
plt.plot(df_sp500)
plt.title('S&P 500 Prices')
從圖中我們可以清楚地看到標(biāo)準(zhǔn)普爾 500 指數(shù)總體呈上升趨勢(shì)奋隶,其中有幾個(gè)點(diǎn)的價(jià)格大幅上漲或下跌。我們可以將這些點(diǎn)視為趨勢(shì)變化點(diǎn)悦荒。鑒于此唯欣,我們先從一個(gè)僅有趨勢(shì)模塊的 NeuralProphet 模型開始,逐漸加入季節(jié)性搬味,AR和節(jié)日模塊境氢,觀察其預(yù)測(cè)表現(xiàn)和API 具體使用。
使用 NeuralProphet碰纬,我們必須確保數(shù)據(jù)的格式包含如下兩列:日期列名ds萍聊,目標(biāo)變量列名 y。
df_sp500 = df_sp500.reset_index().rename(columns={'DATE': 'ds', 'sp500': 'y'})
[圖片上傳失敗...(image-bd5fa0-1672716734981)]
[圖片上傳失敗...(image-4b770e-1672716734981)]
len(df_sp500[~df_sp500.y.isnull()])
>>> 2007
總結(jié) SP 500 數(shù)據(jù)觀察到的特點(diǎn)悦析,后面會(huì)反復(fù)和過程變量做對(duì)比:
總共2080條數(shù)據(jù)中非空數(shù)據(jù)有2007條
開始日期為 2012-12-24寿桨,結(jié)束日期 2020-12-11
在上述有效時(shí)間段內(nèi),非交易的日期(周末强戴,節(jié)日)沒有在列亭螟。
模塊一:趨勢(shì)
使用 NeuralProphet,我們可以通過指定幾個(gè)重要參數(shù)來對(duì)時(shí)間序列數(shù)據(jù)中的趨勢(shì)進(jìn)行建模骑歹。
- n_changepoints — 指定趨勢(shì)發(fā)生變化的點(diǎn)數(shù)预烙。
- trend_reg — 控制趨勢(shì)變化點(diǎn)的正則化參數(shù)。較大的值 (~1–100) 將懲罰更多的變化點(diǎn)陵刹。較小的值 (~0.001–1.0) 將允許更多的變化點(diǎn)默伍。
- changepoints_range — 默認(rèn)值 0.8欢嘿,表示后20%的訓(xùn)練數(shù)據(jù)無 changepoints
model = NeuralProphet(n_changepoints=100,
trend_reg=0.05,
yearly_seasonality=False,
weekly_seasonality=False,
daily_seasonality=False,
epochs=100)
訓(xùn)練模型
df_train, df_val = model.split_df(df_sp500, freq="D", valid_p=0.2)
metrics = model.fit(df_train,
freq='D',
validation_df=df_val,
progress="plot"
)
[站外圖片上傳中...(image-b1612e-1672716734981)]
訓(xùn)練最終趨于穩(wěn)定衰琐。我們來看看 split_df API
的細(xì)節(jié)。
df_train
共1606 行炼蹦,為前 80% 記錄羡宙,df_val
共401 行,為后20% 記錄掐隐,兩者沒有交集狗热,合計(jì) 2007 行數(shù)據(jù),等于 df_sp500
有效數(shù)據(jù)數(shù)虑省。原來默認(rèn)情況下 split_df
會(huì)扔掉 y 值為 NaN 數(shù)據(jù)匿刮。這里兩者沒有交集,大家注意對(duì)比啟用AR后的數(shù)據(jù)切分兩者會(huì)有交集探颈。原有是啟用自回歸后熟丸,預(yù)測(cè)需要過去 k 個(gè)點(diǎn)作為輸入。
預(yù)測(cè)驗(yàn)證集
接著來看看驗(yàn)證集伪节,即 df_val
上的預(yù)測(cè)表現(xiàn)光羞。
future = model.make_future_dataframe(df_sp500, periods=60, n_historic_predictions=True)
forecast = model.predict(future)
fig = model.plot(forecast)
fig.show()
[圖片上傳失敗...(image-6f9fed-1672716734981)]
make_future_dataframe
準(zhǔn)備好待預(yù)測(cè)的數(shù)據(jù)格式绩鸣,參數(shù) periods=60
,n_historic_predictions=True
意義擴(kuò)展 df_sp500 到未來60天后纱兑,同時(shí)保留所有所有現(xiàn)有 df_sp500
的數(shù)據(jù)點(diǎn)呀闻,這些歷史點(diǎn)也將做預(yù)測(cè)。我們 dump 出 make_future_dataframe
后的 future
變量潜慎。
future
序列擴(kuò)展了 df_sp500
捡多,有 y 值的共2007條,和 df_sp500
一致勘纯。時(shí)間擴(kuò)展到了 2021-02-09局服,大約是 2021-12-11 后的60天,這個(gè)也和總條數(shù) 2140 一致驳遵,等于 df_sp500
總條數(shù) 2080 加上 periods=60
的部分淫奔。
接著來看 predict 后的 forecast
變量。y 列依然有 2007 條堤结,多了 yhat1 和 trend 兩列唆迁。
最后,model.plot(forecast)
會(huì)繪制出事實(shí)點(diǎn)和預(yù)測(cè)點(diǎn)的曲線竞穷,注意圖中預(yù)測(cè)值比實(shí)際值要稍長(zhǎng)一些唐责,因?yàn)轭A(yù)測(cè)值到 2021-02-09,實(shí)際值僅到 2020-12-11瘾带。
模塊歸因
fig_components = model.plot_components(forecast)
由于只啟用了趨勢(shì)鼠哥,只有一個(gè)模塊輸出。
很明顯看政,我們的模型捕捉到了標(biāo)準(zhǔn)普爾 500 指數(shù)的總體上漲趨勢(shì)朴恳,但該模型存在欠擬合問題,尤其是當(dāng)我們查看未知未來的60天的預(yù)測(cè)允蚣,更能發(fā)現(xiàn)問題于颖。
僅預(yù)測(cè)未來
同樣的預(yù)測(cè)代碼,將n_historic_predictions
改成 False 會(huì)只預(yù)測(cè)未知未來60天嚷兔。
future = model.make_future_dataframe(df_sp500, periods=60, n_historic_predictions=False)
forecast = model.predict(future)
fig = model.plot(forecast)
fig.show()
print(len(future), len(forecast))
>>> 60 60
根據(jù)上圖森渐,我們可以看到模型對(duì)未來的預(yù)測(cè)遵循一條直線,天天上漲的股票冒晰,還在這里看什么同衣,還不趕緊去買!
模塊二:季節(jié)性
真實(shí)世界的時(shí)間序列數(shù)據(jù)通常涉及季節(jié)性模式壶运。即使對(duì)于股票市場(chǎng)也是如此耐齐,一月效應(yīng)等趨勢(shì)可能會(huì)逐年出現(xiàn)。我們可以通過添加年度季節(jié)性來使之前的模型更加完善。
model = NeuralProphet(n_changepoints=100,
trend_reg=0.05,
yearly_seasonality=True,
weekly_seasonality=False,
daily_seasonality=False,
epochs=100)
df_train, df_val = model.split_df(df_sp500, freq="D", valid_p=0.2)
metrics = model.fit(df_train,
freq='D',
validation_df=df_val,
progress="bar"
)
預(yù)測(cè)驗(yàn)證集
[圖片上傳失敗...(image-9c5c70-1672716734981)]
和之前一條直線相比蚪缀,現(xiàn)在對(duì)數(shù)據(jù)的預(yù)測(cè)顯得更現(xiàn)實(shí)些秫逝。
模塊歸因
現(xiàn)在預(yù)測(cè)的 Y 值是兩個(gè)部分的模塊的加和了。
fig_components = model.plot_components(forecast)
標(biāo)準(zhǔn)普爾 500 指數(shù)預(yù)測(cè)具有年度季節(jié)性询枚,包括歷史數(shù)據(jù)违帆。
僅預(yù)測(cè)未來
[圖片上傳失敗...(image-88a2bd-1672716734981)]
根據(jù)上圖,我們可以看到這個(gè)模型更真實(shí)一些金蜀,但仍然存在欠擬合問題刷后。因此,我們?cè)僖胱曰貧w模型 AR 來進(jìn)一步擬合渊抄。
模塊三:自回歸 AR
AR-Net 是一種用于時(shí)間序列預(yù)測(cè)的自回歸神經(jīng)網(wǎng)絡(luò)尝胆。自回歸模型使用來自過去歷史數(shù)據(jù)點(diǎn)來預(yù)測(cè)后續(xù)點(diǎn),這就是自回歸一詞的來源护桦。
例如含衔,為了預(yù)測(cè)標(biāo)準(zhǔn)普爾 500 指數(shù)的價(jià)格,我們可以訓(xùn)練一個(gè)模型二庵,使用過去 60 天的價(jià)格來預(yù)測(cè)未來 60 天的價(jià)格贪染。分別對(duì)應(yīng)以下代碼中的n_lags和n_forecasts參數(shù)。
model = NeuralProphet(
n_forecasts=60,
n_lags=60,
changepoints_range=0.95,
n_changepoints=100,
yearly_seasonality=True,
weekly_seasonality=False,
daily_seasonality=False,
batch_size=32,
epochs=100,
learning_rate=1.0,
)
訓(xùn)練模型
df_train, df_val = model.split_df(df_sp500, freq="D", valid_p=0.2)
metrics = model.fit(df_train,
freq='D',
validation_df=df_val,
progress="plot"
)
切分訓(xùn)練和驗(yàn)證集代碼一樣催享,但是由于引入 AR杭隙,df_train
,df_val
之間有60條數(shù)據(jù)重合因妙,這是因?yàn)樘翟鳎隍?yàn)證或者預(yù)測(cè)過程中,傳入的 dataframe 前60條不做預(yù)測(cè)攀涵,從61條開始預(yù)測(cè)铣耘,預(yù)測(cè)會(huì)使用當(dāng)前日期前60條作為 AR 模塊的輸入。
len(set(df_train.ds.tolist()).intersection(set(df_val.ds.tolist())))
>>> 60
不過奇怪的是汁果,df_train
加上 df_val
總共有 2305 + 665 = 2970 條記錄涡拘,時(shí)間跨度依然是 2012-12-24 至 2020-12-11玲躯。但是去除重復(fù)的60條記錄后居然剩余2910 條据德, 比 df_sp500
2080 條記錄數(shù)還要多不少。
這里筆者稍微花了點(diǎn)時(shí)間終于弄清楚:df_train
和 df_val
會(huì)填充 2012-12-24 至 2020-12-11 所有的 missing 日期跷车,并使用插值填充 y棘利!
預(yù)測(cè)驗(yàn)證集
這一次,我們將 periods
設(shè)成 0朽缴,也就是不擴(kuò)展 df_sp500
時(shí)間到未知的未來善玫。
future = model.make_future_dataframe(df_sp500, periods=0, n_historic_predictions=True)
forecast = model.predict(future)
forecast
格式變得復(fù)雜,引入了 yhat1, yhat2, ...密强,yhat60茅郎,ar1, ar2, ...蜗元,ar60 等眾多列,這里的60對(duì)應(yīng)于 n_forecasts=60
第一個(gè)預(yù)測(cè)值開始于 forecast
的第61條記錄系冗,對(duì)應(yīng)于 n_lags = 60
forecast[~forecast.yhat1.isnull()]
fig = model.plot(forecast)
fig.show()
模塊歸因
fig_components = model.plot_components(forecast)
[圖片上傳失敗...(image-13de76-1672716734982)]
僅預(yù)測(cè)未來
future = model.make_future_dataframe(df_sp500, periods=60, n_historic_predictions=False)
forecast = model.predict(future)
fig = model.plot(forecast)
fig.show()
[圖片上傳失敗...(image-6ae562-1672716734982)]
模塊四:事件(節(jié)日)
我們還可以配置模型以考慮節(jié)假日因素奕扣,因?yàn)楣?jié)假日很可能會(huì)影響股市走勢(shì)。
model = NeuralProphet(
n_forecasts=60,
n_lags=60,
changepoints_range=0.95,
n_changepoints=100,
yearly_seasonality=True,
weekly_seasonality=False,
daily_seasonality=False,
batch_size=32,
epochs=100,
learning_rate=1.0,
)
model = model.add_country_holidays("US", mode="additive", lower_window=-1, upper_window=1)
只需 add_country_holidays
一條語句就可以啟用預(yù)定義的美國節(jié)假日掌敬。
預(yù)測(cè)驗(yàn)證集
模塊歸因
fig_components = model.plot_components(forecast)
僅預(yù)測(cè)未來
future = model.make_future_dataframe(df_sp500, periods=60, n_historic_predictions=False)
forecast = model.predict(future)
fig = model.plot(forecast)
fig.show()