初識(shí)時(shí)間序列預(yù)測(cè)神器 NeuralProphet 實(shí)戰(zhàn)預(yù)測(cè)股票指數(shù)

更多原創(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>

安裝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')
image

從圖中我們可以清楚地看到標(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é)。

image
image

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=60n_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 變量潜慎。

image
image

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 兩列唆迁。

image

最后,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)
image

由于只啟用了趨勢(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()
image
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)
image

標(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_lagsn_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_traindf_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ù)還要多不少。

image
image

這里筆者稍微花了點(diǎn)時(shí)間終于弄清楚:df_traindf_val 會(huì)填充 2012-12-24 至 2020-12-11 所有的 missing 日期跷车,并使用插值填充 y棘利!

image

預(yù)測(cè)驗(yàn)證集

這一次,我們將 periods 設(shè)成 0朽缴,也就是不擴(kuò)展 df_sp500 時(shí)間到未知的未來善玫。

future = model.make_future_dataframe(df_sp500, periods=0, n_historic_predictions=True)
image
forecast = model.predict(future)
image

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()]
image
fig = model.plot(forecast)
fig.show()
image

模塊歸因

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)證集

image

模塊歸因

fig_components = model.plot_components(forecast)
image

僅預(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
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末惯豆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子奔害,更是在濱河造成了極大的恐慌楷兽,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件华临,死亡現(xiàn)場(chǎng)離奇詭異芯杀,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)雅潭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門瘪匿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寻馏,你說我怎么就攤上這事棋弥。” “怎么了诚欠?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵顽染,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我轰绵,道長(zhǎng)粉寞,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任左腔,我火速辦了婚禮唧垦,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘液样。我一直安慰自己振亮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布鞭莽。 她就那樣靜靜地躺著坊秸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪澎怒。 梳的紋絲不亂的頭發(fā)上褒搔,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼星瘾。 笑死走孽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的琳状。 我是一名探鬼主播融求,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼算撮!你這毒婦竟也來了生宛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤肮柜,失蹤者是張志新(化名)和其女友劉穎陷舅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體审洞,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡莱睁,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了芒澜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仰剿。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痴晦,靈堂內(nèi)的尸體忽然破棺而出南吮,到底是詐尸還是另有隱情,我是刑警寧澤誊酌,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布部凑,位于F島的核電站,受9級(jí)特大地震影響碧浊,放射性物質(zhì)發(fā)生泄漏涂邀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一箱锐、第九天 我趴在偏房一處隱蔽的房頂上張望比勉。 院中可真熱鬧,春花似錦驹止、人聲如沸浩聋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赡勘。三九已至嫂便,卻和暖如春捞镰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國打工岸售, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留践樱,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓凸丸,卻偏偏與公主長(zhǎng)得像拷邢,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子屎慢,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容