Szeregi czasowe — analiza i prognozowanie

Streszczenie

Stacjonarność, ARIMA, autokorelacja, kointegracja i prognozowanie na danych czasowych w R i Python

Specyfika szeregów czasowych

W przekrojowych danych losujemy $n$ niezależnych obserwacji. W szeregach czasowych mamy jedną jednostkę obserwowaną w wielu punktach czasu — obserwacje są ze sobą powiązane.

$$y_1, y_2, y_3, \ldots, y_T$$

To fundamentalna zmiana: PKB w Q2 zależy od PKB w Q1. Ignorowanie tej zależności prowadzi do błędnych wniosków.

Przykłady szeregów czasowych w ekonometrii

  • PKB, inflacja, bezrobocie (kwartalne, roczne)
  • Kursy walut, ceny akcji (dzienne, minutowe)
  • Sprzedaż detaliczna (miesięczna)
  • Stopy procentowe (dzienne)

Stacjonarność

Kluczowa własność — szereg jest stacjonarny, gdy jego własności statystyczne nie zmieniają się w czasie:

$$E[y_t] = \mu \quad \text{(stała średnia)}$$

$$Var(y_t) = \sigma^2 \quad \text{(stała wariancja)}$$

$$Cov(y_t, y_{t-k}) = \gamma_k \quad \text{(autokowariancja zależy tylko od opóźnienia } k\text{)}$$

Znaczenie stacjonarności

Niestacjonarny szereg może prowadzić do regresji pozornej — dwa niezwiązane szeregi wydają się silnie skorelowane, bo oba mają trend.

Klasyczny przykład: ceny akcji i liczba stórek bocianich — oba rosną w czasie, więc $R^2 = 0.95$… ale to czysta koincydencja!

Rodzaje niestacjonarności

Trend deterministyczny (TS — Trend Stationary):

$$y_t = \alpha + \beta t + \varepsilon_t$$

Rozwiązanie: odejmij trend (regresuję na czas)

Błądzenie losowe (DS — Difference Stationary, I(1)):

$$y_t = y_{t-1} + \varepsilon_t$$

Rozwiązanie: pierwsza różnica $\Delta y_t = y_t - y_{t-1}$

Większość makroekonomicznych szeregów to procesy I(1) — zintegrowane rzędu 1.

Test ADF (Augmented Dickey-Fuller)

Testujemy $H_0$: szereg jest niestacjonarny (ma pierwiastek jednostkowy).

$$\Delta y_t = \alpha + \beta t + \rho y_{t-1} + \sum_{j=1}^p \delta_j \Delta y_{t-j} + \varepsilon_t$$

$H_0: \rho = 0$ (pierwiastek jednostkowy, niestacjonarny)

library(tseries)
adf.test(pkb)

# Alternatywnie z pakietem urca (więcej kontroli)
library(urca)
summary(ur.df(pkb, type = "trend", lags = 4, selectlags = "AIC"))

Uwaga: ADF ma słabą moc — mała próba często nie odrzuca $H_0$. Użyj też testu PP (Phillips-Perron) lub KPSS.

Autokorelacja i funkcja ACF

Autokorelacja to korelacja szeregu z jego opóźnioną wersją:

$$\rho_k = Corr(y_t, y_{t-k}) = \frac{Cov(y_t, y_{t-k})}{Var(y_t)}$$

ACF (Autocorrelation Function): wykres $\rho_k$ dla różnych $k$

PACF (Partial ACF): korelacja po wyeliminowaniu pośrednich opóźnień

par(mfrow = c(1, 2))
acf(d_pkb, main = "ACF pierwszej różnicy")
pacf(d_pkb, main = "PACF pierwszej różnicy")

Interpretacja ACF i PACF

ModelACFPACF
AR(p)Zanika geometrycznieUrywa się po opóźnieniu p
MA(q)Urywa się po opóźnieniu qZanika geometrycznie
ARMA(p,q)ZanikaZanika

Model ARIMA

ARIMA(p, d, q) — najpopularniejszy model szeregów czasowych.

  • AR(p): wartość zależy od $p$ poprzednich wartości
  • I(d): d razy różnicujemy żeby uzyskać stacjonarność
  • MA(q): wartość zależy od $q$ poprzednich błędów
$$\Phi(B)(1-B)^d y_t = \Theta(B)\varepsilon_t$$

gdzie $B$ — operator opóźnienia: $By_t = y_{t-1}$.

Przykład AR(1)

$$y_t = \phi y_{t-1} + \varepsilon_t$$
  • $|\phi| < 1$ → stacjonarny
  • $\phi = 1$ → błądzenie losowe (niestacjonarny!)
  • $\phi = 0.9$ → powolny powrót do średniej

Przykład MA(1)

$$y_t = \varepsilon_t + \theta \varepsilon_{t-1}$$

Każda obserwacja to suma bieżącego i poprzedniego szoku.

Dobór rzędu ARIMA

  1. Sprawdź ACF/PACF po różnicowaniu
  2. Użyj kryterium informacyjnego (AIC, BIC):
auto.arima(pkb, ic = "aic")  # automatyczny dobór

Sezonowość — SARIMA

Dane kwartalne lub miesięczne mają często sezonowość — wzorzec powtarzający się co rok.

$$\text{SARIMA}(p,d,q)(P,D,Q)_s$$

gdzie $s$ = 4 (kwartalne) lub 12 (miesięczne), $P,D,Q$ — parametry sezonowe.

# Dekompozycja sezonowa
decomp <- decompose(pkb)
plot(decomp)

# SARIMA
model_s <- auto.arima(pkb, seasonal = TRUE)

Kointegracja — związki długookresowe

Dwa niestacjonarne szeregi $y_t$ i $x_t$ są skointegrowane, jeśli istnieje liniowa kombinacja, która jest stacjonarna:

$$y_t - \beta x_t = z_t \sim I(0)$$

Intuicja ekonomiczna: Ceny konsumenta i producenta obydwa mają trend, ale różnica między nimi jest stacjonarna — są “powiązane” długookresowo.

Test Engla-Grangera

  1. Regresja $y_t$ na $x_t$: $\hat{y}_t = \hat{\alpha} + \hat{\beta} x_t + \hat{z}_t$
  2. Test ADF na resztach $\hat{z}_t$
  3. Jeśli reszty są stacjonarne → kointegracja!
model_koint <- lm(y ~ x)
adf.test(residuals(model_koint))

Model korekty błędem (ECM)

Gdy mamy kointegrację, krótki i długi okres modelujemy razem:

$$\Delta y_t = \alpha + \gamma \hat{z}_{t-1} + \sum_j \delta_j \Delta x_{t-j} + \varepsilon_t$$
  • $\hat{z}_{t-1}$ — odchylenie od równowagi długookresowej
  • $\gamma < 0$ — tempo powrotu do równowagi ($|\gamma|$ = szybkość)

Prognozowanie

Miary jakości prognozy

$$MAE = \frac{1}{h}\sum_t |y_t - \hat{y}_t|$$

$$RMSE = \sqrt{\frac{1}{h}\sum_t (y_t - \hat{y}_t)^2}$$

$$MAPE = \frac{100}{h}\sum_t \left|\frac{y_t - \hat{y}_t}{y_t}\right|$$

Procedura walidacji

# Podziel dane: 80% trening, 20% test
n <- length(pkb)
train <- window(pkb, end = time(pkb)[floor(0.8*n)])
test  <- window(pkb, start = time(pkb)[floor(0.8*n)+1])

model <- auto.arima(train)
prog  <- forecast(model, h = length(test))

# Porównaj z rzeczywistością
accuracy(prog, test)

Nigdy nie oceniaj modelu na danych treningowych! To prowadzi do nadmiernego dopasowania (overfitting).


Następnie: Analiza panelowa — dane wielowymiarowe

📚 Zasoby do nauki
  • Podręcznik: Hamilton, Time Series Analysis
  • Podręcznik: Box, Jenkins, Time Series Analysis: Forecasting and Control
  • YouTube: Forecasting: Principles & Practice
  • R pakiet: forecast, tseries, urca
  • Python: statsmodels.tsa
💻 Kod źródłowy

R:

library(forecast)
library(tseries)

# Wczytaj dane szeregu czasowego
# Przykład: PKB kwartalne
pkb <- ts(c(100, 102, 105, 103, 108, 112, 110, 115), 
           start = c(2020, 1), frequency = 4)

# Test ADF (stacjonarność)
adf.test(pkb)

# Różnicowanie
d_pkb <- diff(pkb)  # pierwsza różnica

# Autokorelacja
acf(pkb)   # ACF
pacf(pkb)  # PACF

# Model ARIMA
model <- auto.arima(pkb)
summary(model)

# Prognoza na 4 okresy
prog <- forecast(model, h = 4)
plot(prog)
print(prog)

Python:

import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller, acf, pacf
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

# Dane
pkb = pd.Series([100, 102, 105, 103, 108, 112, 110, 115],
                 index=pd.date_range('2020-01', periods=8, freq='Q'))

# Test ADF
adf_result = adfuller(pkb)
print(f"ADF stat: {adf_result[0]:.3f}, p-val: {adf_result[1]:.4f}")

# ARIMA(1,1,1)
model = ARIMA(pkb, order=(1, 1, 1)).fit()
print(model.summary())

# Prognoza
forecast = model.forecast(steps=4)
print(forecast)