Time Series Part 3 - Autoregressive Models and Stationarity
Time Series Part 3 - Autoregressive Models and Stationarity
This part of the time series module moves from smoothing to models that use the past to predict the future. We will learn what an autoregressive model is, why stationarity matters, how to test for it, how to fix non-stationary data, and how to read ACF and PACF plots.
1. Session overview
In this guide we will learn:
- What an autoregressive (AR) model is
- Why AR models need stationary data
- How to test for stationarity visually and with statistical tests
- How to make a non-stationary series stationary
- What autocorrelation, ACF, and PACF are
- How to use ACF and PACF to choose the right AR model
2. Introduction to autoregressive models
The basic idea
An autoregressive model uses past values of the series to predict the next value. The word “regressive” comes from regression, and “auto” means on itself. So the model regresses the series on its own past.
AR(1)
The simplest model is AR(1): the value today depends on the value yesterday plus some noise.
y_t = c + φ × y_{t-1} + ε_t
y_tis the value at timetcis a constant (the baseline level)φ(phi) is a parameter that says how much yesterday mattersy_{t-1}is the value one step agoε_tis random noise
Example:
y_t = 2 + 0.8 × y_{t-1} + noise
If yesterday’s value was 10, the model predicts roughly 2 + 0.8 × 10 = 10 today, plus a small random wiggle.
Worked example: generating an AR(1) series
Imagine the process is:
y_t = 5 + 0.6 × y_{t-1} + ε_t
The noise ε_t is small random numbers with mean 0.
Start with y_0 = 12. The next values are:
y_1 = 5 + 0.6 × 12 + ε_1 = 12.2 + small noise
y_2 = 5 + 0.6 × y_1 + ε_2
y_3 = 5 + 0.6 × y_2 + ε_3
Time: 0 1 2 3 4 5
Value: 12 12.2 12.3 12.4 12.4 12.4
Because 0.6 is less than 1, the effect of the starting value 12 dies out and the series settles around its long-run mean of about 12.5.
The long-run mean is:
mean = c / (1 - φ) = 5 / (1 - 0.6) = 12.5
This is why the condition |φ| < 1 is important. If φ = 1, the series has a unit root and is non-stationary. If φ > 1, the series explodes.
AR(p)
An AR(p) model uses the last p values:
y_t = c + φ_1 × y_{t-1} + φ_2 × y_{t-2} + ... + φ_p × y_{t-p} + ε_t
For example, AR(2) uses yesterday and the day before:
y_t = c + φ_1 × y_{t-1} + φ_2 × y_{t-2} + ε_t
The number p is called the order of the model. AR(1), AR(2), and AR(3) are just AR models with different orders.
When can we use an AR model?
AR models work well when:
- The data is stationary (mean and variance are constant over time)
- The relationship between today and the past is roughly linear
- You have enough historical data to estimate the parameters
If the data is not stationary, the AR model can give strange or useless results.
An intuitive example
Consider two versions of the same daily temperature series.
Version A is stationary:
Day: 1 2 3 4 5 6 7
Temp: 20 22 19 21 20 23 21
The mean is about 21. The relationship between today’s temperature and yesterday’s temperature is the same everywhere.
Version B is non-stationary:
Day: 1 2 3 4 5 6 7
Temp: 20 25 31 38 46 55 65
Each day is warmer. A single AR(1) parameter cannot describe today-to-tomorrow for the whole series because the relationship changes as the level rises.
You must remove the trend before fitting an AR model.
3. Stationarity tests
Why stationarity matters
An AR model assumes that the relationship between y_t and y_{t-1} is the same everywhere in the series. If the mean is changing, the relationship is changing. The model cannot learn a single set of parameters that works for the whole series.
Non-stationary: the mean is rising
/
/
/
/
Here, y_t depends on y_{t-1} differently at the start than at the end.
Stationary: the mean is flat
/\ /\ /\ /\ /\
/ \/ \/ \/ \/ \
Here, the relationship between y_t and y_{t-1} is the same everywhere.
Visual check
The simplest test is to look at the plot:
- Is the center roughly flat?
- Is the spread roughly the same?
- Are the waves the same size?
If the answer to all three is yes, the series is probably stationary.
Statistical tests
Augmented Dickey-Fuller (ADF) test
The ADF test checks whether a unit root is present. A unit root usually means the series is non-stationary.
Null hypothesis: the series has a unit root (non-stationary)
Alternative hypothesis: the series is stationary
If the p-value is small (for example, less than 0.05), we reject the null hypothesis and say the series is stationary.
from statsmodels.tsa.stattools import adfuller
result = adfuller(df["value"])
print("p-value:", result[1])
KPSS test
The KPSS test has the opposite logic:
Null hypothesis: the series is stationary
Alternative hypothesis: the series is non-stationary
If the p-value is small, we reject the null hypothesis and say the series is non-stationary.
from statsmodels.tsa.stattools import kpss
result = kpss(df["value"])
print("p-value:", result[1])
It is good practice to use both tests. If they disagree, you need to look more carefully at the plot.
Worked example: interpreting the tests
A stock price series gives:
- ADF p-value = 0.02
- KPSS p-value = 0.04
What do we conclude?
- ADF: small p-value → reject the null of a unit root → the series looks stationary.
- KPSS: small p-value → reject the null of stationarity → the series looks non-stationary.
This is a contradiction. The series might be close to the borderline, or there might be a slow trend. Look at the plot before deciding. If a plot shows a wandering pattern, treat the series as non-stationary and try differencing.
If both tests agreed:
- ADF p-value < 0.05 and KPSS p-value > 0.05 → stationary.
- ADF p-value > 0.05 and KPSS p-value < 0.05 → non-stationary.
4. Dealing with non-stationarity
If a series is not stationary, you can transform it. The goal is to remove the trend or stabilise the variance.
Differencing
Differencing replaces each value with the difference between it and the previous value.
y'_t = y_t - y_{t-1}
Example:
Original: 10, 12, 15, 17, 20, 22
Differenced: 2, 3, 2, 3, 2
If the data has a trend, differencing often makes it stationary. If one round of differencing is not enough, you can difference again.
Worked example: first differencing
Day: 1 2 3 4 5 6 7
Sales: 10 12 15 17 20 22 25
Differenced:
Day 2: 12 - 10 = 2
Day 3: 15 - 12 = 3
Day 4: 17 - 15 = 2
Day 5: 20 - 17 = 3
Day 6: 22 - 20 = 2
Day 7: 25 - 22 = 3
The differenced series is 2, 3, 2, 3, 2, 3. It is now flat around 2.5.
Worked example: second differencing
If the first difference is itself trending, difference again.
Day: 1 2 3 4 5 6 7
Sales: 2 5 9 14 20 27 35
First difference:
Day 2: 5 - 2 = 3
Day 3: 9 - 5 = 4
Day 4: 14 - 9 = 5
Day 5: 20 - 14 = 6
Day 6: 27 - 20 = 7
Day 7: 35 - 27 = 8
First difference: 3, 4, 5, 6, 7, 8 (still increasing)
Second difference:
4 - 3 = 1
5 - 4 = 1
6 - 5 = 1
7 - 6 = 1
8 - 7 = 1
Second difference: 1, 1, 1, 1, 1 (flat and stationary)
A second difference means you are looking at the change of the change. You rarely need more than two rounds.
df["diff"] = df["value"].diff().dropna()
Log transform
If the variance is growing with the level, take the log of the values. This compresses large values and stabilises the spread.
import numpy as np
df["log_value"] = np.log(df["value"])
Detrending
If the data has a clear straight or smooth trend, you can fit a trend line and subtract it.
y'_t = y_t - trend_t
Deseasonalising
If the data has a strong repeating pattern, you can estimate the seasonal effect for each season and subtract it.
y'_t = y_t - seasonal_t
Summary of fixes
| Problem | Fix |
|---|---|
| Trend | Differencing or detrending |
| Growing variance | Log or square-root transform |
| Seasonality | Seasonal differencing or deseasonalising |
5. Autocorrelation measures
What is autocorrelation?
Autocorrelation is the correlation of a series with itself at different time lags. It tells you how much today’s value is related to yesterday’s value, the day before’s, and so on.
Lag 1 autocorrelation: correlation of y_t with y_{t-1}
Lag 2 autocorrelation: correlation of y_t with y_{t-2}
If lag 1 autocorrelation is high, yesterday is a good predictor of today.
ACF: Autocorrelation Function
The ACF shows the autocorrelation for many lags.
ACF plot:
lag 1: ***
lag 2: **
lag 3: *
lag 4: .
lag 5: .
For a stationary AR(1) process, the ACF usually decays gradually:
lag 1: ******
lag 2: *****
lag 3: ****
lag 4: ***
lag 5: **
lag 6: *
For seasonal data, the ACF has spikes at the seasonal lag (for example, lag 12 for monthly data with a yearly pattern).
spikes at lag 12, 24, 36...
lag 12: ******
lag 24: *****
lag 36: ****
PACF: Partial Autocorrelation Function
The PACF is the correlation at a particular lag after removing the effect of the lags in between. It tells you whether that specific lag adds any new information.
For an AR(1) process, the PACF usually has a single significant spike at lag 1:
lag 1: ******
lag 2: .
lag 3: .
lag 4: .
For an AR(2) process, the PACF has significant spikes at lag 1 and lag 2, then drops to zero.
lag 1: ******
lag 2: *****
lag 3: .
lag 4: .
How to use ACF and PACF to choose the AR order
A simple rule of thumb:
- Look at the PACF to choose the order
pof an AR model. - The number of significant spikes in the PACF often tells you what
pshould be. - If the PACF drops to zero after lag 2, try AR(2).
Worked example: reading ACF and PACF
Daily temperature with a one-day memory pattern:
Day: 1 2 3 4 5 6 7
Temp: 20 22 19 21 20 23 21
Imagine the ACF and PACF plots look like this:
ACF:
Lag 1: 0.85 (high)
Lag 2: 0.70 (still high)
Lag 3: 0.55
Lag 4: 0.40
Lag 5: 0.30
PACF:
Lag 1: 0.85 (high)
Lag 2: 0.05 (near zero)
Lag 3: 0.00
Lag 4: 0.00
Lag 5: 0.00
What does this mean?
- The ACF decays slowly, which is typical for an AR(1) process. Today’s temperature is related to yesterday, yesterday’s to the day before, and so on.
- The PACF has one big spike at lag 1 and then drops. That means only the previous day has a direct effect. The relationship at lag 2 is just a knock-on from lag 1.
The pattern “ACF decays, PACF cuts off after lag 1” suggests an AR(1) model.
For an AR(2), you would see:
ACF:
Lag 1: 0.80
Lag 2: 0.65
Lag 3: 0.50
Lag 4: 0.35
Lag 5: 0.25
PACF:
Lag 1: 0.80
Lag 2: 0.40
Lag 3: 0.02
Lag 4: 0.00
The PACF cuts off after lag 2, so try AR(2).
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf
plot_acf(df["value"])
plot_pacf(df["value"])
6. Building an AR model in Python
Once the series is stationary and you have chosen the order p, you can fit the model.
from statsmodels.tsa.ar_model import AutoReg
# Fit an AR(2) model
model = AutoReg(train, lags=2)
fit = model.fit()
print(fit.summary())
# Forecast the next 12 steps
forecast = fit.predict(start=len(train), end=len(train) + 11)
The summary shows the estimated φ values, the constant c, and the p-values. If the p-values are small, the lags are useful predictors.
7. Session summary
- An autoregressive model uses past values of the series to predict the future.
- AR models need the data to be stationary.
- Use visual checks and tests like ADF and KPSS to decide whether a series is stationary.
- If the data is not stationary, use differencing, log transforms, detrending, or deseasonalising.
- ACF shows how the series correlates with itself at different lags.
- PACF shows the direct relationship at a particular lag.
- Use the PACF to choose the order
pof an AR model.
8. One-sentence takeaway
An AR model predicts the future from the past, but only after you have made the series stationary and used ACF/PACF to choose how many past values to include.