天天看點

時間序列的季節性:3種模式及8種模組化方法

作者:deephub

分析和處理季節性是時間序列分析中的一個關鍵工作,在本文中我們将描述三種類型的季節性以及常見的8種模組化方法。

什麼是季節性?

季節性是構成時間序列的關鍵因素之一,是指在一段時間内以相似強度重複的系統運動。

季節變化可以由各種因素引起,例如天氣、月曆或經濟條件。各種應用程式中都有這樣的例子。由于假期和旅遊的緣故,夏天的機票更貴。另一個例子是消費者支出,由于因為12月的假期而增加。

季節性是指某些時期的平均值與其他時期的平均值不同。這個問題導緻該系列是非平穩的。這就是為什麼在建立模型時分析季節性是很重要的。

時間序列的季節性:3種模式及8種模組化方法

3種模式

在時間序列中可以出現三種類型的季節模式。季節性可以是确定性的,也可以是随機的。在随機方面,季節模式可能是平穩的,也可能不是。

這些季節性并不是互相排斥的。時間序列可以同時具有确定性和随機季節性成分。

1、确定的季節性

具有确定性季節性的時間序列具有恒定的季節模式。它總是以一種可預測的方式出現,無論是在強度上還是在周期性上:

相似強度:在同一季節期間,季節+模式的水準保持不變;

不變周期性:波峰和波谷的位置不改變。也就是說季節模式每次重複之間的時間是恒定的。

比如說下面這個就是一個具有确定性季節性的合成月時間序列:

import numpy as np
period = 12
size = 120
beta1 = 0.3
beta2 = 0.6
sin1 = np.asarray([np.sin(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
cos1 = np.asarray([np.cos(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
xt = np.cumsum(np.random.normal(scale=0.1, size=size))
series_det = xt + beta1*sin1 + beta2*cos1 + np.random.normal(scale=0.1, size=size)           
時間序列的季節性:3種模式及8種模組化方法

我們也可以用傅裡葉級數來模拟季節性。傅裡葉級數是不同周期的正弦和餘弦波。如果季節性是确定性的,那麼用傅裡葉級數來描述是非常準确的。

2、随機平穩的季節性

beta1 = np.linspace(-.6, .3, num=size)
beta2 = np.linspace(.6, -.3, num=size)
sin1 = np.asarray([np.sin(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
cos1 = np.asarray([np.cos(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
xt = np.cumsum(np.random.normal(scale=0.1, size=size))
# synthetic series with stochastic seasonality
series_stoc = xt + beta1*sin1 + beta2*cos1 + np.random.normal(scale=0.1, size=size)           
時間序列的季節性:3種模式及8種模組化方法

在連續的季節周期(如一年)中随機平穩的季節性演變。雖然強度難以預測,但周期性大緻保持不變。

有了确定性的季節性,給定月份的預測不會随年份而改變。對于随機平穩季節性,最佳猜測取決于前一年同月的值。

3、随機非平穩季節性

季節模式會在幾個季節期間發生顯著變化,這種季節性的周期性也随着時間的推移而變化。這意味着波峰和波谷的位置不同。

這種季節性模式的例子出現在不同的領域。這些資料包括消費系列或工業生産資料。當時間序列具有綜合季節性時,變化很難預測。

季節性時間序列的測試

可視化時間序列是一種檢查季節模式的簡單方法。但是可視化并不能系統的說明季節性的模式,是以就需要更系統的方法來描述時間序列的而季節性。

1、測量季節強度

我們可以根據以下方法量化季節模式的強度:

import pandas as pd
from statsmodels.tsa.api import STL
def seasonal_strength(series: pd.Series) -> float:
# time series decomposition
series_decomp = STL(series, period=period).fit()

# variance of residuals + seasonality
resid_seas_var = (series_decomp.resid + series_decomp.seasonal).var()
# variance of residuals
resid_var = series_decomp.resid.var()
# seasonal strength
result = 1 - (resid_var / resid_seas_var)
return result           

這個函數估計季節性的強度,不管它是确定性的還是随機的。

# strong seasonality in the deterministic series
seasonal_strength(series_det)
# 0.93
# strong seasonality in the stochastic series
seasonal_strength(series_stoc)
# 0.91           

如果該值高于0.64[2],則需要應用季節性差異過濾器。另一種檢測季節性的方法是QS測試,它在季節性滞後時檢查自相關性。

2、檢測非平穩季節性

有一些統計檢驗是用來檢驗季節模式是否是非平穩的。

一個常見的例子是Canova-Hansen (CH)測試。其假設如下:

  • H0(零假設):季節模式平穩(無季節機關根);
  • H1:該系列包含一個季節性機關根

OCSB測試和HEGY測試是CH的兩種替代方法。這些方法都可以在Python的pmdarima 庫中找到。

from pmdarima.arima import nsdiffs
period = 12 # monthly data
nsdiffs(x=series_det, m=period, test='ch')
nsdiffs(x=series_det, m=period, test='ocsb')
nsdiffs(x=series_stoc, m=period, test='ch')
nsdiffs(x=series_stoc, m=period, test='ocsb')           

函數nsdiffs傳回使序列平穩所需的季節差步數。

3、相關性檢測

還有其他專為季節資料設計的檢測。例如,季節性肯德爾檢驗是一種非參數檢驗,用于檢查季節性時間序列的單調趨勢。

檢測季節性模式

季節性指的是在一段時間内重複出現的模式。這是一個重要的變化來源,對模組化很重要。

時間序列的季節性:3種模式及8種模組化方法

有很多種種處理季節性的方法,其中一些方法在模組化之前去掉了季節成分。經季節調整的資料(時間序列減去季節成分)強調長期影響,如趨勢或商業周期。而另外一些方法增加了額外的變量來捕捉季節性的周期性。

在讨論不同的方法之前,先建立一個時間序列并描述它的季節模式,我們還繼續使用上面的代碼

period = 12 # monthly series
size = 120
beta1 = np.linspace(-.6, .3, num=size)
beta2 = np.linspace(.6, -.3, num=size)
sin1 = np.asarray([np.sin(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
cos1 = np.asarray([np.cos(2 * np.pi * i / 12) for i in np.arange(1, size + 1)])
xt = np.cumsum(np.random.normal(scale=0.1, size=size))
yt = xt + beta1 * sin1 + beta2 * cos1 + np.random.normal(scale=0.1, size=size)
yt = pd.Series(yt)           
時間序列的季節性:3種模式及8種模組化方法

然後通過強度來描述季節模式:

seasonal_strength(yt, period=12)
# 0.90           

結果為0.90,表明季節性确實很強。該時間序列的自相關圖如下圖所示:

時間序列的季節性:3種模式及8種模組化方法

再使用我們上面介紹的Canova-Hansen檢驗來檢視季節性機關根:

from pmdarima.arima import nsdiffs
nsdiffs(x=yt, m=period, test='ch')
# 0           

結果為0,表示不存在季節機關根。也就是說季節模式是平穩的。

那麼,我們該如何應對像這樣的季節性模式呢?

季節性模組化

1、虛拟變量

季節性虛拟變量是一組二進制變量。它們表示一個觀測值是否屬于一個給定的時期(例如一月)。

下面是一個如何建立這些變量的例子:

from sktime.transformations.series.date import DateTimeFeatures
from sklearn.preprocessing import OneHotEncoder
monthly_feats = DateTimeFeatures(ts_freq='M',
keep_original_columns=False,
feature_scope='efficient')
datetime_feats = monthly_feats.fit_transform(yt)
datetime_feats = datetime_feats.drop('year', axis=1)
encoder = OneHotEncoder(drop='first', sparse=False)
encoded_feats = encoder.fit_transform(datetime_feats)
encoded_feats_df = pd.DataFrame(encoded_feats,
columns=encoder.get_feature_names_out(),
dtype=int)           

這段代碼産生如下資料。

時間序列的季節性:3種模式及8種模組化方法

在每個觀察中獲得有關季度和月份的資訊(左側表)。該資訊存儲在datetime_feats對象中。然後使用one-hot編碼來建立虛拟變量(右側表)。

如果季節性是确定的,那麼季節虛拟變量是非常有效。因為确定的季節性種季節模式是固定的,也就是強度和周期性基本不變。并且我們還可以通過檢驗季節虛拟變量的系數來分析季節效應及其變化,這有利于模型的可解釋性。

但是季節性虛拟變量的缺點也很明顯,它假設不同的時期是獨立的。比如1月份的觀測結果與12月份的觀測結果相關。虛拟變量對這種相關性視而不見。是以如果季節模式發生變化,虛拟變量就會産生很多問題。

2、傅裡葉級數

時間序列的季節性:3種模式及8種模組化方法

傅裡葉級數是基于正弦和餘弦波的周期性和确定性的變量。與季節性虛拟變量相反,這些三角函數将季節性模組化為周期性模式,并且這種結構更能反映現實。

sktime中包含了很好的方法:

from sktime.transformations.series.fourier import FourierFeatures
fourier = FourierFeatures(sp_list=[12],
fourier_terms_list=[4],
keep_original_columns=False)
fourier_feats = fourier.fit_transform(yt)           

這裡需要指定兩個主要參數:

  • sp_list:将季節期間作為一個清單(例如,12個月的資料)
  • fourier_terms_list:項的個數,指要包含的正弦和餘弦級數的個數。這些都會影響到表示的平滑度。

傅裡葉級數是可以添加到模型中的解釋變量。并且可以将這些特性與滞後特性結合起來。

3、徑向基函數

徑向基函數(RBF)是傅裡葉級數的替代方法。它他用過建立重複的鐘形曲線來模拟重複的圖案。

在scikit-lego包中有一個RepeatingBasisFunction方法:

from sklego.preprocessing import RepeatingBasisFunction
rbf_encoder = RepeatingBasisFunction(n_periods=4,
column='month_of_year',
input_range=(1, 12),
remainder='drop',
width=0.25)
rbf_features = rbf_encoder.fit_transform(datetime_feats)
rbf_features_df = pd.DataFrame(rbf_features,
columns=[f'RBF{i}'
for i in range(rbf_features.shape[1])])           

該方法最重要的三個參數如下:

  • n_periods:要包含的基函數的個數
  • input_range:列的輸入範圍。例如,在上面的例子中,我們使用(1,12),這是月份的範圍;
  • width:徑向基函數的寬度,主要的作用是控制其平滑度

與傅裡葉級數一樣,RBF變量可以用作模型中的解釋變量。

4、季節性自回歸

自回歸是大多數預測模型的基礎。這個想法是使用最近的過去觀察(滞後)來預測未來的值。這個概念可以擴充到季節性模型。季節性自回歸模型包括同一季節的過去值作為預測因子。

SARIMA是一種流行的方法,它應用了這個想法:

import pmdarima as pm
model = pm.auto_arima(yt, m=12, trace=True)
model.summary()
# Best model: ARIMA(0,1,0)(1,0,0)[12]           

利用季節滞後作為解釋變量是模拟季節性的有效方法。但是在使用這種方法時,應該處理季節性機關根。因為非平穩的資料會産生很多問題。

5、添加額外變量

季節性虛拟變量或傅立葉級數等方法都可以捕捉到周期性模式。但是這些方法都是替代性的方法。

我們也可以通過添加額外變量的方式對季節性進行模組化,例如溫度或每個月的工作日數等外生變量來模拟季節性。

時間序列的季節性:3種模式及8種模組化方法

6、季節性差分

通過在模組化之前從資料中删除季節性來處理季節性。這種方法叫做季節差分。

季節差異是取同一季節連續觀測值之間的差異的過程。這種操作對于去除季節性機關根部特别有用。

可以使用diff方法進行季節差異:

from sklearn.model_selection import train_test_split
from sktime.forecasting.compose import make_reduction
from sklearn.linear_model import RidgeCV
train, test = train_test_split(yt, test_size=12, shuffle=False)
train_sdiff = train.diff(periods=12)[12:]
forecaster = make_reduction(estimator=RidgeCV(),
strategy='recursive',
window_length=3)
forecaster.fit(train_sdiff)
diff_pred = forecaster.predict(fh=list(range(1, 13)))           

我們在差分序列上建立了Ridge回歸模型。通過還原內插補點運算,可以得到原始尺度上的預報。

7、時間序列分解

還可以使用時間序列分解方法(如STL)去除季節性。

差分和分解的差別是什麼?

差分和分解都用于從時間序列中去除季節性。但是轉換後的資料的模組化方式不同。

當應用差分時,模型使用差分資料。是以需要還原差分操作以獲得原始尺度上的預測。

而使用基于分解的方法,需要兩組預測。一個是季節性部分,另一個是季節性調整後的資料。最後的預測是各部分預測的總和。

下面是一個基于分解的方法如何工作的例子:

from statsmodels.tsa.api import STL
from sktime.forecasting.naive import NaiveForecaster
# fitting the seasonal decomposition method
series_decomp = STL(yt, period=period).fit()
# adjusting the data
seas_adj = yt - series_decomp.seasonal
# forecasting the non-seasonal part
forecaster = make_reduction(estimator=RidgeCV(),
strategy='recursive',
window_length=3)
forecaster.fit(seas_adj)
seas_adj_pred = forecaster.predict(fh=list(range(1, 13)))
# forecasting the seasonal part
seas_forecaster = NaiveForecaster(strategy='last', sp=12)
seas_forecaster.fit(series_decomp.seasonal)
seas_preds = seas_forecaster.predict(fh=list(range(1, 13)))
# combining the forecasts
preds = seas_adj_pred + seas_preds           

在這個例子中,我們建立了一個Ridge 回歸模型來預測經季節調整後的資料。然後将兩個預測加在一起。

8、動态線性模型(DLM)

回歸模型的參數通常是靜态的。它們不随時間變化,或者是時不變的。DLM是線性回歸的一種特殊情況。其主要特點是參數随時間而變化,而不是靜态的。

dlm假定季節性時間序列的結構随季節而變化。是以合理的方法是建立具有時變參數的模型。随季節變化的參數。

參考文獻[4]中的書的第15章提供了這種方法的一個簡潔的R示例。他們使用時變的MARSS(多元自回歸狀态空間)方法來模拟季節性變化。

總結

時間序列模組化并不是一項簡單的任務,它需要考慮多個因素和技術。季節性的存在可以對時間序列資料的分析和預測産生重要影響。識别和了解季節性模式有助于揭示資料的周期性變化、制定季節性調整政策以及進行更準确的預測。時間序列模組化往往需要結合經驗和領域知識,同時靈活運用不同的技術和方法,以獲得準确、可靠的模型和預測結果。

作者:Vitor Cerqueira

引用:

[1] Canova, F. and Hansen, Bruce E. (1995) “Are seasonal patterns constant over time? A test for seasonal stability”. Journal of Business & Economic Statistics, 13(3), pp. 237–252

[2] Wang, X, Smith, KA, Hyndman, RJ (2006) “Characteristic-based clustering for time series data”, Data Mining and Knowledge Discovery, 13(3), 335–364.

[3] Holmes, Elizabeth E., Mark D. Scheuerell, and E. J. Ward. “Applied time series analysis for fisheries and environmental data.” NOAA Fisheries, Northwest Fisheries Science Center, Seattle, WA (2020).

[4] Holmes, Elizabeth E., Mark D. Scheuerell, and E. J. Ward. “Applied time series analysis for fisheries and environmental data.” NOAA Fisheries, Northwest Fisheries Science Center, Seattle, WA (2020).

繼續閱讀