Stationarity in Time Series — Tests and Transformations
Statistics
Making Time Series Ready for Modeling
Stationarity — constant mean, variance, and autocorrelation over time — is a prerequisite for most forecasting models. ADF and KPSS tests detect non-stationarity, while differencing and transformations restore it.
-
Economic Forecasting — Transform non-stationary GDP data for reliable ARIMA modeling
-
Financial Analysis — Convert price series to stationary returns for volatility modeling
-
Climate Science — Remove trends from temperature data to analyze cyclical patterns
Stationary series are predictable because their statistical properties don't wander.
A time series is stationary if its statistical properties (mean, variance, autocorrelation) do not change over time. Stationarity is a key assumption for many time series models.
Why Stationarity Matters
Non-stationary series often exhibit:
-
Trend: systematic increase or decrease in mean
-
Seasonality: periodic fluctuations
-
Heteroscedasticity: changing variance over time
Augmented Dickey-Fuller (ADF) Test
The ADF test checks for a unit root, which indicates non-stationarity.
| Hypothesis | Meaning |
|-----------|---------|
| : | Unit root present -> non-stationary |
| : | No unit root -> stationary |
KPSS Test
The KPSS test has opposite hypotheses from the ADF test.
| Hypothesis | Meaning |
|-----------|---------|
| : Series is stationary | Trend-stationary |
| : Series is non-stationary | Unit root present |
Transformations for Stationarity
Differencing
For seasonal data, use seasonal differencing:
Log Transformation
Stabilizes variance when it increases with the level of the series.
Box-Cox Transformation
A family of power transformations that includes log as a special case.
Python Implementation
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.tsa.stattools import adfuller, kpss
np.random.seed(42)
# Non-stationary series (random walk + trend)
t = np.arange(200)
Y = np.cumsum(np.random.randn(200)) + 0.02 * t
# ADF test
adf_result = adfuller(Y, autolag='AIC')
print(f"ADF Statistic: {adf_result[0]:.3f}")
print(f"p-value: {adf_result[1]:.4f}")
# KPSS test
kpss_result = kpss(Y, regression='ct', nlags='auto')
print(f"KPSS Statistic: {kpss_result[0]:.3f}")
print(f"p-value: {kpss_result[1]:.4f}")
# Apply differencing
Y_diff = np.diff(Y)
adf_diff = adfuller(Y_diff, autolag='AIC')
print(f"\nAfter differencing:")
print(f"ADF p-value: {adf_diff[1]:.4f}")
Worked Example
Key Takeaways
Related Topics
-
See ARIMA Models for models that handle non-stationary data
-
See ACF and PACF for identifying autocorrelation patterns
-
See Seasonal Decomposition for separating trend, seasonal, and residual components