Szeregi czasowe — analiza i prognozowanie
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
| Model | ACF | PACF |
|---|---|---|
| AR(p) | Zanika geometrycznie | Urywa się po opóźnieniu p |
| MA(q) | Urywa się po opóźnieniu q | Zanika geometrycznie |
| ARMA(p,q) | Zanika | Zanika |
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
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
- Sprawdź ACF/PACF po różnicowaniu
- 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
- Regresja $y_t$ na $x_t$: $\hat{y}_t = \hat{\alpha} + \hat{\beta} x_t + \hat{z}_t$
- Test ADF na resztach $\hat{z}_t$
- 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
- 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
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)