ADF Test

Ulf Hamster 2 min.
python adf test stationarity time series augmented dickey fuller test

Load Packages

from statsmodels.tsa.stattools import adfuller
import numpy as np

import matplotlib.pyplot as plt
%matplotlib inline

Just Noise (No Trend)

The p-value is very small, close to zero (rejects H0), i.e. the time series is stationary.

X = np.random.normal(loc=10, scale=1, size=(500,))
plt.plot(X);

png

adf, pval, usedlags, _, _, _ = adfuller(X, regression='c', autolag='BIC')
print(f"p-value: {pval}")
print(f"ADF stats: {adf}")
print(f"used lags: {usedlags}")
p-value: 0.0
ADF Statistic: -23.7100657709607
used lags: 0

Noise + Trend

The p-value is much larger than 0.0 (fails to reject H0), i.e. the time series is non-stationary.

X = np.random.normal(loc=10, scale=1, size=(500,)) + np.arange(500) * 0.01
plt.plot(X);

png

# BIC is faster than AIC
adf, pval, usedlags, _, _, _ = adfuller(X, regression='c', autolag='BIC')
print(f"p-value: {pval}")
print(f"ADF stats: {adf}")
print(f"used lags: {usedlags}")
p-value: 0.4163142678417643
ADF Statistic: -1.7288469718738826
used lags: 7

How much trend is needed?

%%time
n_obs = 500
f_min, f_max, n_trial = 0.001, 0.01, 20
for f in range(n_trial+1):
    # generate trendy noise
    factor = f/n_trial * (f_max - f_min) + f_min
    trend = + np.arange(n_obs) * factor
    noise = np.random.normal(loc=10, scale=1, size=(n_obs,))
    X = noise + trend
    # ADF test
    adf, pval, _, _, _, _ = adfuller(X, regression='c', autolag='BIC')
    # show results
    print("trend: {:5.4f} | p-values: {:5.4f} | ADF: {:>6.3f}".format(factor, pval, adf))
trend: 0.0010 | p-values: 0.0000 | ADF: -21.930
trend: 0.0015 | p-values: 0.0000 | ADF: -20.644
trend: 0.0019 | p-values: 0.0000 | ADF: -22.965
trend: 0.0024 | p-values: 0.0000 | ADF: -20.385
trend: 0.0028 | p-values: 0.0000 | ADF: -9.195
trend: 0.0033 | p-values: 0.0000 | ADF: -9.142
trend: 0.0037 | p-values: 0.0000 | ADF: -6.034
trend: 0.0042 | p-values: 0.0000 | ADF: -6.832
trend: 0.0046 | p-values: 0.0000 | ADF: -5.345
trend: 0.0051 | p-values: 0.0073 | ADF: -3.526
trend: 0.0055 | p-values: 0.1307 | ADF: -2.440
trend: 0.0060 | p-values: 0.0506 | ADF: -2.856
trend: 0.0064 | p-values: 0.6322 | ADF: -1.293
trend: 0.0069 | p-values: 0.0319 | ADF: -3.034
trend: 0.0073 | p-values: 0.2435 | ADF: -2.103
trend: 0.0078 | p-values: 0.4104 | ADF: -1.740
trend: 0.0082 | p-values: 0.1010 | ADF: -2.563
trend: 0.0087 | p-values: 0.1338 | ADF: -2.429
trend: 0.0091 | p-values: 0.4612 | ADF: -1.642
trend: 0.0095 | p-values: 0.3763 | ADF: -1.808
trend: 0.0100 | p-values: 0.8182 | ADF: -0.803
CPU times: user 830 ms, sys: 88.6 ms, total: 919 ms
Wall time: 623 ms

Links