Cross-Correlation
An online retailer notices that a burst of search queries for "winter coat" reliably shows up about
two weeks before a jump in coat sales. If they could measure that lead precisely they could
stock the warehouse just in time. This is the everyday job of cross-correlation:
given two time series, at what lag does one most strongly track the other, and which one
leads? The
autocorrelation
function asked how a series relates to its own past; cross-correlation asks how
one series relates to another series' past and future.
Cross-covariance and the CCF
For two jointly stationary series x_t and
y_t, the cross-covariance function at lag
h is
\gamma_{xy}(h) = \operatorname{Cov}(x_t,\; y_{t+h}) = \mathbb{E}\big[(x_t - \mu_x)(y_{t+h} - \mu_y)\big].
Standardize it by the two individual standard deviations and you get the
cross-correlation function (CCF), a dimensionless number in
[-1, 1]:
\rho_{xy}(h) = \frac{\gamma_{xy}(h)}{\sqrt{\gamma_{xx}(0)\,\gamma_{yy}(0)}} = \frac{\gamma_{xy}(h)}{\sigma_x \sigma_y}.
With the convention above, a nonzero value at lag h says: the value of
x now is correlated with the value of y
h steps later. Slide h across a range
of lags, plot the result, and the shape tells you the lead–lag structure at a glance.
The crucial asymmetry
An autocorrelation function is always symmetric: \rho_x(h) = \rho_x(-h),
because "how does today relate to h steps away" doesn't care which
direction you look. The CCF is not symmetric — and that asymmetry is the entire
point:
- In general \gamma_{xy}(h) \neq \gamma_{xy}(-h) — the function need
not be a mirror image about lag zero.
- The correct symmetry swaps the roles of the two series:
\gamma_{xy}(h) = \gamma_{yx}(-h).
- A peak at a positive lag h > 0 means
x leads y by
h; a peak at negative lag means
y leads x.
A symmetric CCF would tell you two series move together but not who moves first. The
lopsidedness is what encodes the direction of timing — the coat searches peaking before the coat
sales, not the other way round.
A CCF that leans right
The stem plot below is the sample CCF of two series where x drives
y with a two-step delay. Notice it is not centred on lag zero:
the tallest stem sits at h = +2, and the values decay away on either side
of that peak. Everything to the right of zero is telling you about
x's future influence on y; the small,
fast-fading values to the left rule out the reverse story.
Worked example: reading a peak at lag +2
Suppose a study of two indicators reports a sample CCF that is small and flat everywhere except for a
clear spike \hat\rho_{xy}(2) = 0.7, with much smaller values at
h = 1 and h = 3 and essentially nothing at
negative lags. Read it step by step:
- The peak is at a positive lag, so x leads
y — movements in x come first.
- The lead is two steps: today's x is most correlated
with y two periods from now,
\operatorname{Corr}(x_t, y_{t+2}) = 0.7.
- The near-zero values at negative lags say y carries little
information about the future of x — the relationship runs one
way.
Operationally: to forecast y you should put lagged
x in the model. That is precisely the intuition
Granger
causality will formalize into a test.
Cross-correlation is even more prone to the spurious-relationship trap than ordinary correlation. If
x and y each carry a trend or are strongly
autocorrelated, the sample CCF will light up with large, smooth, "significant"-looking values at
many lags — even when the two series have nothing to do with each other. The reason is subtle: the
usual \pm 1.96/\sqrt{n} significance bands assume at least one
series is white noise, and heavy autocorrelation inflates the true variance of
\hat\rho_{xy}(h) far beyond that. The fix is
prewhitening: fit a model to x to reduce it to
(near-)white residuals, apply the same filter to y, and compute
the CCF of the two filtered series. Only after prewhitening does a CCF peak actually mean what you
think it means. Interpreting a raw CCF between two trending series is the same mistake as a
spurious
regression in stem-plot clothing.
Almost — and the near-miss trips people up. Cross-correlation slides one signal past another and
multiplies:
(x \star y)(h) = \sum_t x_t\, y_{t+h}. Convolution does the same but with
one signal reversed: (x * y)(h) = \sum_t x_t\, y_{h-t}. That flip
is exactly why convolution is symmetric (x*y = y*x) while
cross-correlation is not. Engineers use cross-correlation to find the delay between two
copies of a signal — sonar, GPS, matching a template to an image — which is the same lead–lag
question a statistician asks of two time series, wearing a different hat.