porphet论文_时间序列模型Prophet使用详细讲解
目錄
一、簡易入門
二、飽和預測
2.1 預測飽和增長
2.2?預測飽和減少
三、趨勢突變點
3.1?Prophet 中的自動監測突變點
3.2?調整趨勢的靈活性
3.3?指定突變點的位置
四、季節性,假期效果和回歸量
4.1 對假期和特征事件建模
4.2 季節性的傅里葉級數
4.3?自定義季節性因素
4.4?對節假日和季節性設定先驗規模
4.5?附加的回歸量
五、乘法季節性
六、預測區間
6.1 趨勢的不確定性
6.2 季節的不確定性
七、異常值
八、非日數據
8.1 子日數據
8.2?有規則間隔的數據
8.3?月數據
九、診斷
十、與機器學習算法的對比
一、簡易入門
Prophet 遵循?sklearn?庫建模的應用程序接口。我們創建了一個 Prophet 類的實例,其中使用了“擬合模型”?fit?和“預測”?predict?方法。
Prophet 的輸入量往往是一個包含兩列的數據框:ds?和?y?。ds?列必須包含日期(YYYY-MM-DD)或者是具體的時間點(YYYY-MM-DD HH:MM:SS)。?y?列必須是數值變量,表示我們希望去預測的量。
下面實例中使用的是?佩頓 · 曼寧的維基百科主頁?每日訪問量的時間序列數據(2007/12/10 - 2016/01/20)。我們使用 R 中的?Wikipediatrend?包獲取該數據集。這個數據集具有多季節周期性、不斷變化的增長率和可以擬合特定日期(例如佩頓 · 曼寧的決賽和超級碗)的情況等 Prophet 適用的性質,因此可以作為一個不錯的例子。(注:佩頓 · 曼寧為前美式橄欖球四分衛)
首先,我們導入數據,該數據已經做過了log處理(即,做過df['y'] = np.log(df['y'])操作)。
# Python
import pandas as pd
from fbprophet import Prophet
# 讀入數據集
df = pd.read_csv('examples/example_wp_log_peyton_manning.csv')
df.head()
通過對一個 Prophet 對象進行實例化來擬合模型,任何影響預測過程的設置都將在構造模型時被指定。接下來,就可以使用?fit?方法代入歷史數據集來擬合模型,擬合過程應當花費 1 - 5 秒。
# 擬合模型
m = Prophet()
m.fit(df)
預測過程則需要建立在包含日期?ds?列的數據框基礎上。通過使用輔助的方法?Prophet.make_future_dataframe?來將未來的日期擴展指定的天數,得到一個合規的數據框。默認情況下,這樣做會自動包含歷史數據的日期,因此我們也可以用來查看模型對于歷史數據的擬合效果。
# 構建待預測日期數據框,periods = 365 代表除歷史數據的日期外再往后推 365 天
future = m.make_future_dataframe(periods=365)
future.tail()
predict?方法將會對每一行未來?future?日期得到一個預測值(稱為?yhat?)。如果你傳入了歷史數據的日期,它將會提供樣本的模型擬合值。預測?forecast?創建的對象應當是一個新的數據框,其中包含一列預測值?yhat?,以及成分的分析和置信區間。
# 預測數據集
forecast = m.predict(future)
forecast[['ds', 'yhat', 'yhat_lower', 'yhat_upper']].tail()
通過?Prophet.plot?方法傳入預測得到的數據框,可以對預測的效果進行繪圖。
# 展示預測結果
m.plot(forecast);
如果想查看預測的成分分析,可以使用?Prophet.plot_components?方法。默認情況下,將展示趨勢、時間序列的年度季節性和周季節性。如果之前包含了節假日,也會展示出來。
# 預測的成分分析繪圖,展示預測中的趨勢、周效應和年度效應
m.plot_components(forecast);
注: 一個很核心的問題是我們應該怎么樣理解上圖的3個子圖。通過對forecast這個Dataframe分析我們就可以得到結論。
我們先看下forecast都有哪些列。
print(forecast.columns)
Index(['ds', 'trend', 'trend_lower', 'trend_upper', 'yhat_lower', 'yhat_upper',
'additive_terms', 'additive_terms_lower', 'additive_terms_upper',
'multiplicative_terms', 'multiplicative_terms_lower',
'multiplicative_terms_upper', 'weekly', 'weekly_lower', 'weekly_upper',
'yearly', 'yearly_lower', 'yearly_upper', 'yhat'],
dtype='object')
通過對數據的分析,我們就可以知道:
①圖1是根據trend畫出來的,圖2是根據weekly畫出來的,圖3是根據yearly畫出來的。
②因為是加法模型,有:forecast['additive_terms'] = forecast['weekly'] + forecast['yearly'];有:forecast['yhat']? = forecast['trend'] +??forecast['additive_terms'] 。因此:forecast['yhat']? = forecast['trend'] +forecast['weekly'] + forecast['yearly']。
如果有節假日因素,那么就會有forecast['yhat']? = forecast['trend'] +forecast['weekly'] + forecast['yearly'] + forecast['holidays']。
在第四部分,我們會講到節假日因素,對于那些是節假日的天數,forecast['holidays']才會有值,不是節假日的天數,forecast['holidays']為0。
③因為是加法模型,'multiplicative_terms', 'multiplicative_terms_lower', 'multiplicative_terms_upper'這3列為空。
因此,基于上面的分析,weekly中的Monday為0.3的意思就是,在trend的基礎上,加0.3;Saturday為-0.3的意思就是,在trend的基礎上,減0.3。因此,這條線的高低也在一定程度上反應了“銷量的趨勢“。
注:許多方法的細節可以通過help(Prophet) 或者?help(Prophet.fit)?來獲得。
二、飽和預測
2.1 預測飽和增長
默認情況下, Prophet 使用線性模型進行預測。當預測增長情況時,通常會存在可到達的最大極限值,例如:總市場規模、總人口數等等。這被稱做承載能力(carrying capacity),那么預測時就應當在接近該值時趨于飽和。
Prophet 可使用?logistic 增長?趨勢模型進行預測,同時指定承載能力。下面使用?R 語言的維基百科主頁?訪問量(取對數)的實例來進行說明。
首先,我們導入數據,該數據已經做過了log處理(即,做過df['y'] = np.log(df['y'])操作)。
import pandas as pd
from fbprophet import Prophet
df = pd.read_csv('examples/example_wp_log_R.csv')
新建一列?cap?來指定承載能力的大小。本實例中假設取某個特定的值,通常情況下這個值應當通過市場規模的數據或專業知識來決定。
df['cap'] = 8.5
值得注意的是數據框的每行都必須指定?cap?的值,但并非需要是恒定值。如果市場規模在不斷地增長,那么?cap?也可以是不斷增長的序列。
如之前教程所述來擬合模型,并且通過一個新增的參數來指定采用 logistic 增長:
m = Prophet(growth='logistic')
m.fit(df)
如前所述,我們可以創建一個數據框來預測未來值,不過這里要指定未來的承載能力。我們將未來的承載能力設定得和歷史數據一樣,并且預測未來 3 年的數據。
future = m.make_future_dataframe(periods=1826)
future['cap'] = 8.5
fcst = m.predict(future)
fig = m.plot(fcst)
預測結果如下圖所示:
2.2?預測飽和減少
logistic增長模型還可以處理飽和最小值,方法與指定最大值的列的方式相同:
# Python
df['y'] = 10 - df['y']
df['cap'] = 6
df['floor'] = 1.5
future['cap'] = 6
future['floor'] = 1.5
m = Prophet(growth='logistic')
m.fit(df)
fcst = m.predict(future)
fig = m.plot(fcst)
結果如下圖:
三、趨勢突變點
在之前的部分,我們可以發現真實的時間序列數據往往在趨勢中存在一些突變點。默認情況下, Prophet 將自動監測到這些點,并對趨勢做適當地調整。不過,要是對趨勢建模時發生了一些問題,例如:Prophet 不小心忽略了一個趨勢速率的變化或者對歷史數據趨勢變化存在過擬合現象。如果我們希望對趨勢的調整過程做更好地控制的話,那么下面將會介紹幾種可以使用的方法。
3.1?Prophet 中的自動監測突變點
Prophet 首先是通過在大量潛在的突變點(變化速率突變)中進行識別來監測突變點的。之后對趨勢變化的幅度做稀疏先驗(等同于 L1 正則化)——實際上 Prophet 在建模時會存在很多變化速率突變的點,但只會盡可能少地使用它們。以 第一部分中佩頓 · 曼寧的數據為例,默認下, Prophet 會識別出 25 個潛在的突變點(均勻分布在在前 80% 的時間序列數據中)。下圖中的豎線指出這些潛在的突變點所在的位置。
雖然存在很多變化速率可能會突變的點,但由于做了稀疏先驗,絕大多數突變點并不會包含在建模過程中。如下圖所示,通過觀察對每個突變點繪制的速率變化值圖,可以發現這一點。
潛在突變點的數量可以通過設置?n_changepoints?參數來指定,但最好還是利用調整正則化過程來修正。
顯著的突變點的位置可以通過以下代碼獲得:
# Python
from fbprophet.plot import add_changepoints_to_plot
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)
默認情況下,只有在時間序列的前80%才會推斷出突變點,以便有足夠的長度來預測未來的趨勢,并避免在時間序列的末尾出現過度擬合的波動。這個默認值可以在很多情況下工作,但不是所有情況下都可以,可以使用changepoint_range參數進行更改。例如,Python中的m = Prophet(changepoint_range=0.9)。這意味著將在時間序列的前90%處尋找潛在的變化點。
3.2?調整趨勢的靈活性
如果趨勢的變化被過度擬合(即過于靈活)或者擬合不足(即靈活性不夠),可以利用輸入參數?changepoint_prior_scale?來調整稀疏先驗的程度。默認下,這個參數被指定為 0.05 。
增加這個值,會導致趨勢擬合得更加靈活。代碼和圖如下所示:
df = pd.read_csv('examples/example_wp_log_peyton_manning.csv')
# 擬合模型
m = Prophet(changepoint_prior_scale=0.5)
m.fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
fig = m.plot(forecast)
減少這個值,會導致趨勢擬合得靈活性降低。代碼和圖如下所示:
m = Prophet(changepoint_prior_scale=0.001)
m.fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
m.plot(forecast);
3.3?指定突變點的位置
如果你希望手動指定潛在突變點的位置而不是利用自動的突變點監測,可以使用?changepoints?參數。
代碼和圖如下所示:
m = Prophet(changepoints=['2014-01-01'])
m.fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
m.plot(forecast);
四、季節性,假期效果和回歸量
4.1 對假期和特征事件建模
如果需要專門對節假日或者其它的事件進行建模,你就必須得為此創建一個新的dataframe,其中包含兩列(節假日?holiday?和日期戳?ds?),每行分別記錄了每個出現的節假日。這個數據框必須包含所有出現的節假日,不僅是歷史數據集中還是待預測的時期中的。如果這些節假日并沒有在待預測的時期中被注明, Prophet 也會利用歷史數據對它們建模,但預測未來時卻不會使用這些模型來預測。
注:也就是說,在待預測的日期里,我們也必須指定所有出現的節假日。
你可以在這個數據框基礎上再新建兩列?lower_window?和?upper_window?,從而將節假日的時間擴展成一個區間 [?lower_window?,?upper_window?] 。舉例來說,如果想將平安夜也加入到 “圣誕節” 里,就設置?lower_window = -1 , upper_window = 0?;如果想將黑色星期五加入到 “感恩節” 里,就設置?lower_window = 0 , upper_window = 1?。
下面我們創建一個數據框,其中包含了所有佩頓 · 曼寧參加過的決賽日期:
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))
上述代碼中,我們將超級碗的日期既記錄在了決賽的日期數據框中,也記錄在了超級碗的日期數據框中。這就會造成超級碗日期的效應會在決賽日期的作用下疊加兩次。
一旦這個數據框創建好了,就可以通過傳入?holidays?參數使得在預測時考慮上節假日效應。這里我們仍以第一部分中佩頓 · 曼寧的數據為例:
df = pd.read_csv('examples/example_wp_log_peyton_manning.csv')
m = Prophet(holidays=holidays)
m.fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
可通過?forecast?數據框,來展示節假日效應:
# 看一下假期的最后10行數據
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][
['ds', 'playoff', 'superbowl']][-10:]
在成分分析的圖中,如下所示,也可以看到節假日效應。我們可以發現,在決賽日期附近有一個穿透,而在超級碗日期時穿透則更為明顯。
fig = m.plot_components(forecast)
可以使用?plot_forecast_component(從fbprophet.plot導入)來畫出獨立的節假日的成分。類似如下代碼:
from fbprophet.plot import plot_forecast_component
m.plot_forecast_component(forecast, 'superbowl')
4.2 季節性的傅里葉級數
季節性是用部分傅里葉和估計的。有關完整的細節,請參閱論文,以及維基百科上的這個圖,以說明部分傅里葉和如何近似于一個線性周期信號。部分和(order)中的項數是一個參數,它決定了季節性的變化有多快。為了說明這一點,?我們仍似乎用第一部分中佩頓 · 曼寧的數據。每年季節性的默認傅立葉級數是10,這就產生了這樣的擬合:
# Python
from fbprophet.plot import plot_yearly
m = Prophet().fit(df)
a = plot_yearly(m)
默認值10通常是合適的,但是當季節性需要適應更高頻率的變化時,它們可以增加,并且通常不那么平滑。在實例化模型時,可以為每個內置季節性指定傅立葉級數,這里增加到20:
from fbprophet.plot import plot_yearly
m = Prophet(yearly_seasonality=20).fit(df)
a = plot_yearly(m)
可以看到,曲線更加的多變了。增加傅立葉項的數量可以使季節性適應更快的變化周期,但也可能導致過度擬合:N個傅立葉項對應于用于建模周期的2N個變量。
4.3?自定義季節性因素
如果時間序列超過兩個周期,Prophet將默認適合每周和每年的季節性。對于子日(sub-daily )時間序列,它也將適合每日的季節性。在Python中,可以使用add_seasality方法添加其它季節性(如每月、每季、每小時)。
這個函數的輸入是一個名字,季節性的周期,以及季節性的傅里葉order。作為參考,默認情況下,Prophet為周季節性設定的傅立葉order為3,為年季節性設定的為10。add_seasality的一個可選輸入是該季節性組件的先驗規模。
作為一個例子,我們仍使用佩頓 · 曼寧的數據,但是用每月的季節性替換每周的季節性。每月的季節性將出現在組件圖中:
m = Prophet(weekly_seasonality=False)
m.add_seasonality(name='monthly', period=30.5, fourier_order=5)
forecast = m.fit(df).predict(future)
fig = m.plot_components(forecast)
4.4?對節假日和季節性設定先驗規模
如果發現節假日效應被過度擬合了,通過設置參數?holidays_prior_scale?可以調整它們的先驗規模來使之平滑,默認下該值取 10 。
減少這個參數會降低假期效果:
m = Prophet(holidays=holidays, holidays_prior_scale=0.05).fit(df)
forecast = m.predict(future)
forecast[(forecast['playoff'] + forecast['superbowl']).abs() > 0][
['ds', 'playoff', 'superbowl']][-10:]
代碼輸出結果如下所示:
和之前相比,節假日效應的規模被減弱了,特別是對觀測值較少的超級碗而言。類似的,還有一個?seasonality_prior_scale?參數可以用來調整模型對于季節性的擬合程度。
可以通過在節假日的dataframe中包含一個列prior_scale來單獨設置先驗規模。獨立的季節性的先驗規模可以作為add_seasonality的參數傳遞。例如,可以使用以下方法設置每周季節性的先驗規模:
m = Prophet()
m.add_seasonality(
name='weekly', period=7, fourier_order=3, prior_scale=0.1)
4.5?附加的回歸量
可以使用add_regressor方法將附加的回歸量添加到模型的線性部分。包含回歸值的列需要同時出現在擬合數據格式(fit)和預測數據格式(predict)中。例如,我們可以在NFL賽季的周日添加附加的效果。在成分圖上,這種效果會出現在“extra_regre_”圖中:
# 判斷是否是NFL賽季的周日
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)
NFL周日也可以使用之前描述的“節假日”的接口,通過創建一個過去和未來NFL周日的list。add_regressor函數為定義附加的線性回歸函數提供了一個更通用的接口,特別是它不要求回歸函數是二進制指示器。
add_regressor函數具有可選的參數,用于指定先驗規模(默認情況下使用節假日先驗規模),和指定是否標準化回歸量。help(Prophet.add_regressor)可以查看相關參數。
附加的回歸量必須要知道歷史和未來的日期。因此,它要么是已知未來值(比如nfl_sunday),要么是其他地方已經單獨預測出的結果。如果回歸量在整個歷史中都是不變的,則Prophet會引發一個錯誤,因為沒有任何東西可以fit它。
附加的回歸量被放在模型的線性分量中,所以依賴于附加的回歸量時間序列作為底層模型的加法或乘法因子。
五、乘法季節性
默認情況下,Prophet能夠滿足附加的季節性,這意味著季節性的影響是加到趨勢中得到了最后的預報(yhat)。航空旅客數量的時間序列是一個附加的季節性不起作用的例子:
df = pd.read_csv('../examples/example_air_passengers.csv')
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(50, freq='MS')
forecast = m.predict(future)
fig = m.plot(forecast)
這個時間序列有一個明顯的年度周期,但預測中的季節性在時間序列開始時太大,在結束時又太小。在這個時間序列中,季節性并不是Prophet所假定的是一個恒定的加性因子,而是隨著趨勢在增長。這就是乘法季節性(multiplicative seasonality)。
Prophet可以通過設置seasonality_mode='multiplicative'來建模乘法季節性:
m = Prophet(seasonality_mode='multiplicative')
m.fit(df)
forecast = m.predict(future)
fig = m.plot(forecast)
看一下乘法的成分圖:
fig = m.plot_components(forecast)
與第一部分對成分圖分析類似,我們這里對乘法模型的成分圖進行一個分析:
①圖1是根據trend畫出來的,圖2是根據yearly畫出來的。
②因為是乘法模型,有:forecast['multiplicative_terms'] = forecast['yearly'];因此:forecast['yhat']? = forecast['trend'] * (1+forecast['multiplicative_terms'])。
使用seasonality_mode='multiplicative',節假日也將被建模為乘法效果。
③因為是乘法模型,'additive_terms', 'additive_terms_lower', 'additive_terms_upper'這3列為0。
默認情況下,任何添加的季節性或額外的回歸量都可以使用seasality_mode設置為加法或者是乘法。但假如在添加季節性或回歸量時,可以通過指定mode=' addiative '或mode=' ative'作為參數來覆蓋之前的設定。
例如,這個模塊將內置的季節性設置為乘法,但使用一個附加的季度季節性來覆蓋原本的乘法,這時候季度季節性就是加法了。
# Python
m = Prophet(seasonality_mode='multiplicative')
m.add_seasonality('quarterly', period=91.25, fourier_order=8, mode='additive')
額外的加法的季度季節性將出現在成分圖的單獨的面板上。
這個時候是時間序列的混合模型:forecast['yhat'] =?forecast['trend'] ?* (1+forecast['multiplicative_terms']) + forecast['additive_terms']。
六、預測區間
默認情況下, Prophet 的返回結果中會包括預測值?yhat?的預測區間。當然,預測區間的估計需建立在一些重要的假設前提下。
在預測時,不確定性主要來源于三個部分:趨勢中的不確定性、季節效應估計中的不確定性和觀測值的噪聲影響。
6.1 趨勢的不確定性
預測中,不確定性最大的來源就在于未來趨勢改變的不確定性。在之前的時間序列實例中,我們可以發現歷史數據具有明顯的趨勢性。 Prophet 能夠監測并去擬合它,但是我們期望得到的趨勢改變究竟會如何走向呢?或許這是無解的,因此我們盡可能地做出最合理的推斷,假定 “未來將會和歷史具有相似的趨勢” 。尤其重要的是,我們假定未來趨勢的平均變動頻率和幅度和我們觀測到的歷史值是一樣的,從而預測趨勢的變化并通過計算,最終得到預測區間。
這種衡量不確定性的方法具有以下性質:變化速率靈活性更大時(通過增大參數?changepoint_prior_scale?的值),預測的不確定性也會隨之增大。原因在于如果將歷史數據中更多的變化速率加入了模型,也就代表我們認為未來也會變化得更多,就會使得預測區間成為反映過擬合的標志。
預測區間的寬度(默認下,是 80% )可以通過設置?interval_width?參數來控制:
m = Prophet(interval_width=0.95).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
由于預測區間估計時假定未來將會和過去保持一樣的變化頻率和幅度,而這個假定可能并不正確,所以預測區間的估計不可能完全準確。
6.2 季節的不確定性
默認情況下, Prophet 只會返回趨勢中的不確定性和觀測值噪聲的影響。你必須使用貝葉斯取樣的方法來得到季節效應的不確定性,可通過設置?mcmc.samples?參數(默認下取 0 )來實現。下面使用佩頓 · 曼寧的數據為例:
m = Prophet(mcmc_samples=500).fit(df)
future = m.make_future_dataframe(periods=365)
forecast = m.predict(future)
# 報錯:UnboundLocalError: local variable 'pool' referenced before assignment
上述代碼將最大后驗估計( MAP )取代為馬爾科夫蒙特卡洛取樣 ( MCMC ),并且將計算時間從 10 秒延長到 10 分鐘。
如果做了全取樣,就能通過繪圖看到季節效應的不確定性了:
m.plot_components(forecast);
可以使用m.predictive_samples(future)方法在Python中訪問原始的后驗預測樣本。
在PyStan有一些針對Windows的上游問題,這使得MCMC采樣非常緩慢。在Windows中,MCMC采樣的最佳選擇是在Linux VM中使用R或Python。
因此,我的上述代碼會出錯,季節的不確定性在我windows的python中跑不動,暫時忽略,了解即可。
七、異常值
異常值主要通過兩種方式影響 Prophet 預測結果。下面我們使用之前使用過的 R 語言維基百科主頁對數訪問量的數據來建模預測,只不過使用存在時間間隔并不完整的數據:
df = pd.read_csv('examples/example_wp_log_R_outliers1.csv')
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=1096)
forecast = m.predict(future)
m.plot(forecast);
如上輸出圖所示,趨勢預測看似合理,預測區間的估計卻過于廣泛。 Prophet 雖能夠處理歷史數據中的異常值,但僅僅是將它們與趨勢的變化擬合在一起,認為未來也會有類似的趨勢變化。
處理異常值最好的方法是移除它們,而 Prophet 是能夠處理缺失數據的。如果在歷史數據中某行的值為空(?NA?),但是在待預測日期數據框?future?中仍保留這個日期,那么 Prophet 依舊可以給出該行的預測值。
# 將2010年一年的數據設為缺失
df.loc[(df['ds'] > '2010-01-01') & (df['ds'] < '2011-01-01'), 'y'] = None
model = Prophet().fit(df)
model.plot(model.predict(future));
上述這個實例雖然影響了不確定性的估計,卻沒有影響到主要的預測值?yhat?。但是,現實往往并非如此,接下來,在上述數據集基礎上加入新的異常值后再建模預測:
df = pd.read_csv('examples/example_wp_log_R_outliers2.csv')
m = Prophet()
m.fit(df)
future = m.make_future_dataframe(periods=1096)
forecast = m.predict(future)
m.plot(forecast);
這里 2015年 6 月存在一些異常值破壞了季節效應的估計,因此未來的預測也會永久地受到這個影響。最好的解決方法就是移除這些異常值:
# 將2015年前半年的數據設為缺失
df.loc[(df['ds'] > '2015-06-01') & (df['ds'] < '2015-06-30'), 'y'] = None
m = Prophet().fit(df)
m.plot(m.predict(future));
八、非日數據
8.1 子日數據
Prophet可以通過在ds列中傳遞一個帶有時間戳的dataframe來對時間序列進行子日(Sub-daily)觀測。時間戳的格式應該是YYYY-MM-DD - HH:MM:SS。當使用子日數據時,日季節性將自動匹配。在這里,我們用5分鐘的分辨率數據集(約塞米蒂的每日溫度)對Prophet進行數據匹配:
df = pd.read_csv('examples/example_yosemite_temps.csv')
m = Prophet(changepoint_prior_scale=0.01).fit(df)
future = m.make_future_dataframe(periods=300, freq='H')
fcst = m.predict(future)
fig = m.plot(fcst)
成分圖中的日季節性:
fig = m.plot_components(fcst)
8.2?有規則間隔的數據
假設上面的數據集只有每天早上6點之前的觀測值:
df2 = df.copy()
df2['ds'] = pd.to_datetime(df2['ds'])
# 只保留每天早上6點之前的數據
df2 = df2[df2['ds'].dt.hour < 6]
m = Prophet().fit(df2)
future = m.make_future_dataframe(periods=300, freq='H')
fcst = m.predict(future)
fig = m.plot(fcst)
這個預測看起來很差,未來的波動比歷史上看到的要大得多。這里的問題是,我們將每天的循環安排在一個時間序列中,這個時間序列中只有一天的一部分數據(12a到6a)。因此,每天的季節性在一天剩下的時間里是不受約束的,估計也不準確。解決方案是只對有歷史數據的時間窗進行預測。這里,這意味著限制未來dataframe的時間(從12a到6a):
future2 = future.copy()
future2 = future2[future2['ds'].dt.hour < 6]
fcst = m.predict(future2)
fig = m.plot(fcst)
同樣的原理也適用于數據中有規則間隔的其他數據集。例如,如果歷史只包含工作日,那么應該只對工作日進行預測,因為不會很好地估計每周的季節性。
8.3?月數據
可以使用Prophet來匹配每月的數據。然而,Prophet 的基本模型是連續時間的,這意味著如果將模型與每月的數據相匹配,然后要求每天的預測,我們會得到奇怪的結果。
下面使用美國零售業銷售量數據來預測未來 10 年的情況:
df = pd.read_csv('examples/example_retail_sales.csv')
m = Prophet().fit(df)
future = m.make_future_dataframe(periods=3652)
fcst = m.predict(future)
m.plot(fcst);
預測結果看起來非常雜亂,原因正是在于這個特殊的數據集使用的是月數據。當我們擬合年度效應時,只有每個月第一天的數據,而且對于其他天的周期效應是不可測且過擬合的。當你使用 Prophet 擬合月度數據時,可以通過在?make_future_dataframe?中傳入頻率參數只做月度的預測。
future = m.make_future_dataframe(periods=120, freq='M')
fcst = m.predict(future)
m.plot(fcst);
九、診斷
Prophet包含時間序列交叉驗證功能,以測量使用歷史數據的預測誤差。這是通過在歷史記錄中選擇截止點來完成的,對于每一個都只使用該截止點之前的數據來擬合模型。然后,我們可以將預測值與實際值進行比較。這張圖展示了對Peyton Manning數據集的模擬歷史預測,該模型適用于5年的初始歷史,并在1年的時間范圍內進行了預測。
源論文中進一步描述了模擬的歷史預測。
這個交叉驗證過程可以使用cross_validation函數自動完成一系列歷史截斷。我們指定預測水平(horizon),然后選擇初始訓練期(initial)的大小和截斷之間的間隔(period)。默認情況下,初始訓練期設置為horizon的三倍,每半個horizon就有一個截斷。
注:這里需要解釋下horizon,initial和period的意義:initial代表了一開始的時間是多少,period代表每隔多長時間設置一個cutoff,horizon代表每次從cutoff往后預測多少天。
cross_validation的輸出是一個dataframe,在每個模擬預測日期和每個截斷日期都有真實值y和樣本預測值yhat。特別地,對在cutoff 和cutoff + horizon之間的每一個觀測點都進行了預測。然后,這個dataframe可以用來度量yhat和y的錯誤。
在這里,我們做交叉驗證來評估預測horizon在365天的性能,從第一次截止時730天的訓練數據開始,然后每180天進行一次預測。在這個8年的時間序列中,這相當于11個總預測。
注:Peyton Manning數據一共大約8年多(2007/12/10 - 2016/01/20)的數據。
根據上面對horizon,initial和period的解釋:容易得到為什么是11個總預測。因為最后一個也要預測365天,所有最后一個cutoff在2015-01-20,從2007-12-19數730天是2010-02-15,則在2010-02-15到2015-01-20共有1800天,對應著10個cutoff,最后1個cutoff在2015-01-20,因此共11個cutoff。
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(m, initial='730 days', period='180 days', horizon = '365 days')
df_cv.head()
performance_metrics作為離截止點(預測的未來距離)的函數,可用于計算關于預測性能的一些有用統計數據(如與y相比時yhat、yhat_lower和yhat_upper)。計算得到的統計信息包括均方誤差(mean squared error, MSE)、均方根誤差(root mean squared error, RMSE)、平均絕對誤差(mean absolute error, MAE)、平均絕對誤差(mean absolute percent error, MAPE)以及yhat_lower和yhat_upper估計的覆蓋率。這些都是在df_cv中通過horizon (ds - cutoff)排序后預測的滾動窗口中計算出來的。默認情況下,每個窗口都會包含10%的預測,但是可以通過rolling_window參數來更改。
from fbprophet.diagnostics import performance_metrics
df_p = performance_metrics(df_cv)
df_p.head()
交叉驗證性能指標可以用plot_cross_validation_metric可視化,這里顯示的是MAPE。點表示df_cv中每個預測的絕對誤差百分比。藍線顯示的是MAPE,均值被取到滾動窗口的圓點。我們可以看到,對于一個月后的預測,誤差在5%左右,而對于一年之后的預測,誤差會增加到11%左右。
# Python
from fbprophet.plot import plot_cross_validation_metric
fig = plot_cross_validation_metric(df_cv, metric='mape')
圖中滾動窗口的大小可以通過可選參數rolling_window更改,該參數指定在每個滾動窗口中使用的預測比例。默認值為0.1,即每個窗口中包含的df_cv的10%行;增大值得話將導致圖中平均曲線更平滑。
初始周期應該足夠長,以捕獲模型的所有特性,特別是季節性和額外的回歸變量:對年的季節性至少保證一年,對周的季節性至少保證一周,等等。
十、與機器學習算法的對比
與先進的機器學習算法如LGBM相比,Prophet作為一個時間序列的工具,優點就是不需要特征工程就可以得到趨勢,季節因素和節假日因素,但是這同時也是它的缺點之一,它無法利用更多的信息,如在預測商品的銷量時,無法利用商品的信息,門店的信息,促銷的信息等。
因此,尋找一種融合的方法是一個迫切的需求。
————————————————
版權聲明:本文為CSDN博主「anshuai_aw1」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/anshuai_aw1/article/details/83412058
總結
以上是生活随笔為你收集整理的porphet论文_时间序列模型Prophet使用详细讲解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux vim卸载安装包_Linux
- 下一篇: 联发科射频工程师题目_联发科技笔试题