本期作者:Eric Brown
本期編輯:Allen | 崙
系列1:我用Facebook開源神器Prophet,預測時間序列基於Python
數據基於標普500指數:
import pandas as pd import numpy as np from fbprophet import Prophet import matplotlib.pyplot as plt %matplotlib inline plt.rcParams['figure.figsize']=(20,10) plt.style.use('ggplot')
market_df = pd.read_csv('../examples/SP500.csv', index_col='DATE', parse_dates=True) df = market_df.reset_index().rename(columns={'DATE':'ds', 'SP500':'y'}) df['y'] = np.log(df['y']) #lets take a look at our data quickly df.set_index('ds').y.plot()
運行Prophet
model = Prophet() model.fit(df); future = model.make_future_dataframe(periods=366) forecast = model.predict(future)
Prophet已經創建了所需的模型並匹配數據。Prophet在默認情況下爲我們創建了變化點並將它們存儲在.changepoints中。默認情況下,Prophet在初始數據集的80%中添加了25個變化點。在初始化prophet時,可以使用n_changepoints參數更改點的數量(例如,model= prophet (n_changepoints=30))
model.changepoints
70 2009-03-20 141 2009-07-01 211 2009-10-09 281 2010-01-21 352 2010-05-04 422 2010-08-12 492 2010-11-19 563 2011-03-04 633 2011-06-14 703 2011-09-22 774 2012-01-04 844 2012-04-16 914 2012-07-25 984 2012-11-05 1055 2013-02-19 1125 2013-05-30 1195 2013-09-09 1266 2013-12-18 1336 2014-04-01 1406 2014-07-11 1477 2014-10-21 1547 2015-02-02 1617 2015-05-13 1688 2015-08-24 1758 2015-12-02 Name: ds, dtype: datetime64[ns]
除了查看變化點的日期之外,我們還可以查看添加了變化點的圖表:
figure = model.plot(forecast) for changepoint in model.changepoints: plt.axvline(changepoint,ls='--', lw=1)
看看上面圖表中可能的變化點,我們可以看到它們與一些高點和低點非常吻合。你還可以使用以下代碼查看這個可視化:
deltas = model.params['delta'].mean(0) fig = plt.figure(facecolor='w') ax = fig.add_subplot(111) ax.bar(range(len(deltas)), deltas) ax.grid(True, which='major', c='gray', ls='-', lw=1, alpha=0.2) ax.set_ylabel('Rate change') ax.set_xlabel('Potential changepoint') fig.tight_layout()
從上面的圖表中我們可以看到,有相當多的變化點在10到20之間,它們的幅度非常小,在預測中最容易被忽視。
現在,如果我們知道過去的趨勢發生了什麼變化,我們可以將這些已知的變化點添加到dataframe中。對於這些數據,注:事實上,低或高並不意味着它是一個真正的變化點或趨勢變化,但讓我們假設它是。
m = Prophet(changepoints=['2009-03-09', '2010-07-02', '2011-09-26', '2012-03-20', '2010-04-06']) forecast = m.fit(df).predict(future) m.plot(forecast) figure = m.plot(forecast) for changepoint in m.changepoints: plt.axvline(changepoint,ls='--', lw=1)
我們可以看到,通過手動設置我們的變化點與使用自動檢測變化點相比,我們對模型進行了巨大的更改。除非你非常確定過去的趨勢變化點,最好使用Prophet提供的默認值。
Prophet對趨勢變化點的使用是非常棒的,特別是那些信號/數據集在信號的生命週期中有顯著的變化。也就是說,除非你能確定你的變化點,否則最好讓Prophet自動去完成。
預測市場
還是使用標普500指數:
df = market_df.reset_index().rename(columns={'DATE':'ds', 'SP500':'y'}) df['y'] = np.log(df['y']) model = Prophet() model.fit(df); future = model.make_future_dataframe(periods=365) #forecasting for 1 year from now. forecast = model.predict(future) figure=model.plot(forecast)
根據現有的數據,很難看出預測(藍線)和實際數據(黑點)的關係。讓我們看一下過去800個數據點(大約2年)的預測和實際預測,而不看未來的預測:
two_years = forecast.set_index('ds').join(market_df) two_years = two_years[['SP500', 'yhat', 'yhat_upper', 'yhat_lower' ]].dropna().tail(800) two_years['yhat']=np.exp(two_years.yhat) two_years['yhat_upper']=np.exp(two_years.yhat_upper) two_years['yhat_lower']=np.exp(two_years.yhat_lower) two_years[['SP500', 'yhat']].plot()
你可以從上面的圖表中看到,預測很好地遵循了趨勢,但似乎不太擅長捕捉市場的“波動”。如果我們對“順應趨勢”,而不是試圖完美地把握高峯和低谷,這對我們來說可能是件好事。
讓我們來看看一些測量準確度的方法:
two_years_AE = (two_years.yhat - two_years.SP500) print two_years_AE.describe() count 800.000000 mean -0.540173 std 47.568987 min -141.265774 25% -29.383549 50% -1.548716 75% 25.878416 max 168.898459 dtype: float64
再來看看一些更精確的測量方法。使用sklearn的r2_score函數的R-squared:
r2_score(two_years.SP500, two_years.yhat) 0.90563333683064451
R-squared看起來不錯,在任何第一輪建模中,都會取0.9。
現在我們來看看均值平方誤差:
mean_squared_error(two_years.SP500, two_years.yhat) 2260.2718233576029
現在,讓我們看看平均絕對誤差(MAE)。能讓我們更好地瞭解錯誤率,而不是標準平均值。
mean_absolute_error(two_years.SP500, two_years.yhat) 36.179476001483771
MAE還告訴我們,通過Prophet預測交易並不理想。
另一種查看該預測有效性的方法是根據實際值繪製預測的上置信區間和下置信區間。可以通過繪製yhat_upper和yhat_lower來實現。
fig, ax1 = plt.subplots() ax1.plot(two_years.SP500) ax1.plot(two_years.yhat) ax1.plot(two_years.yhat_upper, color='black', linestyle=':', alpha=0.5) ax1.plot(two_years.yhat_lower, color='black', linestyle=':', alpha=0.5) ax1.set_title('Actual S&P 500 (Orange) vs S&P 500 Forecasted Upper & Lower Confidence (Black)') ax1.set_ylabel('Price') ax1.set_xlabel('Date')
你不能從這張圖表中看出任何可以量化的東西,但你可以對預測的價值做出判斷。如果你想做短線交易(1天到幾周),這個預測幾乎是無用的,但是如果你的投資時間是幾個月到幾年,這個預測可能會提供一些價值,以更好地瞭解市場的趨勢和預測的趨勢。
讓我們回過頭來看看實際的預測,看看它是否能告訴我們一些與預測和實際數據不同的東西。
fig, ax1 = plt.subplots() ax1.plot(full_df.SP500) ax1.plot(full_df.yhat, color='black', linestyle=':') ax1.fill_between(full_df.index, np.exp(full_df['yhat_upper']), np.exp(full_df['yhat_lower']), alpha=0.5, color='darkgray') ax1.set_title('Actual S&P 500 (Orange) vs S&P 500 Forecasted (Black) with Confidence Bands') ax1.set_ylabel('Price') ax1.set_xlabel('Date') L=ax1.legend() L.get_texts()[0].set_text('S&P 500 Actual') L.get_texts()[1].set_text('S&P 5600 Forecasted')
這個圖比默認的Prophet表圖容易理解。我們可以看到,在實際價值和預測的歷史中,Prophet做了一個不錯的預測但是在市場變得非常不穩定的時候,它的表現很一般。
具體看一下未來的預測,Prophe告訴我們市場將繼續上升,在預測期結束時應該在2750左右,區間從2000到4000左右。也許我們可以更準確地使用每週或每月的數據預測。