How to Check Stationarity of Data in Python: ADF Test Explained
When working with time series data, one of the first things you need to check is whether the data is stationary. Stationarity is a critical assumption for many time series models and forecasting techniques. In this article, we‘ll dive deep into the concept of stationarity, why it matters, and how to test for it in Python using the Augmented Dickey-Fuller (ADF) test.
Understanding Stationarity
In simple terms, a time series is stationary if its statistical properties do not change over time. More formally, stationarity can be defined in two ways:
-
Strong stationarity (strict stationarity): A time series is strongly stationary if the joint probability distribution does not change when shifted in time. In other words, the mean, variance, and other moments are constant over time.
-
Weak stationarity (covariance stationarity): A time series is weakly stationary if its mean and autocovariance do not vary with respect to time. This is a less stringent condition than strong stationarity.
For practical purposes, weak stationarity is often sufficient. A weakly stationary time series has the following properties:
- Constant mean: E(Xt) = μ for all t
- Constant variance: Var(Xt) = σ^2 for all t
- Constant autocovariance: Cov(Xt, Xt+k) = γ(k) for all t and any lag k
Here are some examples of stationary and non-stationary time series:
- Daily temperature readings: Generally stationary, as the mean and variance are relatively constant over time
- Stock prices: Typically non-stationary, as the mean and variance often increase over time
- White noise: Perfectly stationary, as it has zero mean, constant variance, and no autocorrelation
Modeling non-stationary data can lead to spurious regressions, where the model looks good on paper but is actually meaningless. Stationarity ensures that the model‘s properties are stable and predictions are reliable.
Methods to Check Stationarity
There are several ways to check if a time series is stationary:
- Plotting the data: A quick visual check can reveal obvious trends, seasonality, or changing variance
- Summary statistics: Comparing the mean, variance, and autocorrelations at different time periods
- ACF/PACF plots: Examining the autocorrelation and partial autocorrelation plots for significant lags
- Unit root tests: Formal statistical tests to detect non-stationarity, such as the ADF test, KPSS test, and PP test
In this article, we‘ll focus on the Augmented Dickey-Fuller (ADF) test, which is a popular unit root test used to assess stationarity. The ADF test extends the original Dickey-Fuller test to accommodate higher-order autoregressive processes.
Augmented Dickey-Fuller (ADF) Test
The ADF test checks for the presence of a unit root in a time series. If a unit root is present, the series is considered non-stationary. The null and alternative hypotheses of the ADF test are:
- Null hypothesis (H0): The series has a unit root (non-stationary)
- Alternative hypothesis (H1): The series does not have a unit root (stationary)
The ADF test is based on the following regression equation:
Δyt = α + βt + γyt-1 + δ1Δyt-1 + ... + δp-1Δyt-p+1 + εt
Where:
- yt is the time series at time t
- α is a constant term
- βt is a deterministic time trend
- p is the lag order
- εt is the error term
The key parameter of interest is γ. If γ = 0, the series contains a unit root and is non-stationary. The ADF test statistic is the t-statistic for the γ coefficient. If the test statistic is more negative than the critical value at a given significance level, we reject the null hypothesis and conclude that the series is stationary.
Let‘s see how to conduct the ADF test in Python using the statsmodels library:
from statsmodels.tsa.stattools import adfuller
# Perform ADF test
result = adfuller(data)
# Extract test results
test_statistic = result[0]
p_value = result[1]
lags_used = result[2]
n_obs = result[3]
critical_values = result[4]
# Print test results
print(f‘ADF Test Statistic: {test_statistic:.3f}‘)
print(f‘p-value: {p_value:.3f}‘)
print(f‘Number of lags used: {lags_used}‘)
print(f‘Number of observations used: {n_obs}‘)
print(‘Critical values:‘)
for key, value in critical_values.items():
print(f‘ {key}: {value:.3f}‘)
The adfuller function returns the following values:
- Test statistic: The ADF test statistic
- p-value: The probability value of the test statistic
- Number of lags used: The number of lags used in the regression
- Number of observations used: The number of observations used in the test
- Critical values: The critical values for the test statistic at different significance levels
To interpret the results, compare the test statistic to the critical values. If the test statistic is more negative than the critical value at a chosen significance level (e.g., 1%, 5%, or 10%), reject the null hypothesis and conclude that the series is stationary. Alternatively, if the p-value is less than the significance level, reject the null hypothesis.
Here‘s an example of how to visualize the ADF test results using matplotlib:
import matplotlib.pyplot as plt
# Plot the time series
plt.figure(figsize=(12, 6))
plt.plot(data)
plt.title(‘Time Series‘)
plt.xlabel(‘Time‘)
plt.ylabel(‘Value‘)
# Add ADF test results as text
adf_text = f‘ADF Test Statistic: {test_statistic:.3f}\np-value: {p_value:.3f}‘
plt.figtext(0.15, 0.8, adf_text, fontsize=12, bbox=dict(facecolor=‘white‘, edgecolor=‘black‘))
plt.tight_layout()
plt.show()
This code will plot the time series and display the ADF test statistic and p-value on the plot.
Other Considerations
When testing for stationarity, there are a few other things to keep in mind:
-
Seasonal data: If the data exhibits seasonality, you may need to use seasonal differencing or seasonal decomposition before applying the ADF test. Seasonal differencing involves subtracting the value of a time series from its value one or more seasonal periods ago.
-
Structural breaks: Stationarity can be affected by structural breaks, which are sudden shifts in the mean or variance of a time series. If structural breaks are present, the ADF test may not be reliable. In such cases, modified unit root tests like the Zivot-Andrews test can be used.
-
Transformations: If a time series is non-stationary, it may be possible to transform it into a stationary series. Common transformations include differencing (subtracting each value from the previous value) and detrending (removing the linear trend). However, transformations should be used judiciously, as they can affect the interpretation of the model.
Conclusion
Checking for stationarity is a crucial step in time series analysis. The Augmented Dickey-Fuller (ADF) test is a widely used unit root test to assess whether a time series is stationary. By comparing the test statistic to critical values or examining the p-value, you can determine if the series contains a unit root and is non-stationary.
When using the ADF test in Python, the statsmodels library provides an easy-to-use implementation. Remember to interpret the test results carefully and consider the specific characteristics of your data, such as seasonality and structural breaks.
It‘s always a good idea to test for stationarity using multiple methods to confirm the results. Plotting the data, examining summary statistics, and looking at ACF/PACF plots can provide additional insights.
Finally, keep in mind that stationarity is just one aspect of time series modeling. Other factors, such as autocorrelation, seasonality, and external influences, also play a crucial role in building accurate and reliable models.
By understanding stationarity and mastering the ADF test in Python, you‘ll be well-equipped to tackle a wide range of time series problems and make informed decisions based on your data.