02 — Foundations

Autocorrelation (ACF/PACF)#

FoundationsStatistical 1 min read
◆ The PatternMeasuring how a series remembers its own past

The autocorrelation function (ACF) measures correlation between a series and its lagged values. The partial autocorrelation function (PACF) removes the influence of intermediate lags. Together they reveal the memory structure and guide ARIMA order selection.

ACF(k) = Cov(yt, yt−k) / Var(yt)
ACF at lag k is the Pearson correlation between a series and itself shifted by k steps. Values outside the confidence band are significant.
// Interactive — ACF and PACF plots
AR Order (p)1
MA Order (q)0
PatternACFPACFModel
Slow decayGeometrically decayingCuts off at lag pAR(p)
Sharp cutoffCuts off at lag qGeometrically decayingMA(q)
Both decayDecaysDecaysARMA(p,q)
Pattern bridge: ACF/PACF diagnoses for time series are like correlation analysis in statistics — but with yourself across time. In markets, momentum indicators are practical autocorrelation measurements. Where autocorrelation is zero, a streak says nothing about the next step — the trap of the gambler’s fallacy.
Worked example

2,000 points from an AR(1) process with φ = 0.7. The sample ACF at lags 1–3 is 0.698, 0.486, 0.345, against a theoretical 0.7, 0.49, 0.343 — a geometric decay. The PACF at lag 2 is −0.003: once lag 1 is known, lag 2 adds nothing, which is how the plot identifies an AR(1). The usual significance band is ±0.044.

Where it misleads
  • The ±1.96/√n band assumes white noise and is checked at many lags at once; a few “significant” spikes are expected by chance.
  • Trend and seasonality dominate the ACF; read it after making the series stationary.
  • ACF and PACF patterns are clear for textbook processes and ambiguous for real data; use them to shortlist models, then compare forecasts.
In code
rng = np.random.default_rng(1)
n, phi = 2_000, 0.7
y = np.zeros(n)
for t in range(1, n): y[t] = phi * y[t - 1] + rng.normal()   # AR(1)

def acf(x, k):
    x = x - x.mean(); return (x[:-k] * x[k:]).sum() / (x * x).sum()

sample = [round(acf(y, k), 3) for k in (1, 2, 3)]
theory = [round(phi ** k, 3) for k in (1, 2, 3)]
X = np.column_stack([y[1:-1], y[:-2]])           # PACF at lag 2: the lag-2 coefficient given lag 1
pacf2 = np.linalg.lstsq(X, y[2:], rcond=None)[0][1]
band = 1.96 / np.sqrt(n)
Python, in your browser — edit the code and run it again

Assumes import numpy as np and import pandas as pd. Each snippet simulates or makes up its own series, as the comments say.

The same idea with a library
# Python — ACF/PACF plots
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

fig, axes = plt.subplots(1, 2, figsize=(12, 4))
plot_acf(series, lags=30, ax=axes[0])
plot_pacf(series, lags=30, method='ywm', ax=axes[1])
plt.tight_layout()
Sources
  • Time Series Analysis: Forecasting and Control (5th ed.), G. E. P. Box, G. M. Jenkins, G. C. Reinsel & G. M. Ljung, Wiley, 2015
  • G. M. Ljung & G. E. P. Box, “On a Measure of Lack of Fit in Time Series Models”, Biometrika 65(2), 1978
  • Forecasting: Principles and Practice (3rd ed.), R. J. Hyndman & G. Athanasopoulos, OTexts, 2021

Last reviewed October 2026 · How this site checks its content · Report a mistake

Check yourself

1. For an AR(1) process with φ = 0.7, what is the autocorrelation at lag 2?

Show answer

C. In an AR(1), the autocorrelation at lag k is φk: 0.7² = 0.49. It decays geometrically.

2. The PACF cuts off after lag 2 while the ACF decays slowly. Which model does that suggest?

Show answer

A. For AR(p) the partial autocorrelations vanish after lag p; for MA(q) it is the ACF that cuts off after lag q.

3. What should the residuals of a good forecasting model look like?

Show answer

A. A Ljung–Box test on the residuals is the usual check: they should look like white noise.

Linked from 1
← Previous
Stationarity
Open in the full reader, with the topic sidebar