Granger Causality — Time Series Causality Testing
Statistics
Testing Whether One Time Series Predicts Another
Granger causality tests whether past values of one series improve predictions of another. It's a statistical notion of predictive causality that reveals lead-lag relationships in temporal data.
-
Economics — Test whether money supply growth Granger-causes inflation
-
Finance — Detect lead-lag relationships between stock markets across time zones
-
Neuroscience — Identify information flow directions between brain regions
If knowing X's past helps predict Y's future, X Granger-causes Y — a powerful test of temporal influence.
Granger causality tests whether past values of one time series help predict future values of another. It is a statistical notion of causality, not true causal inference.
Formal Definition
Consider forecasting using its own past and the past of :
Hypothesis Test
| Hypothesis | Conclusion |
|-----------|-----------|
| : | does NOT Granger-cause |
| : At least one | Granger-causes |
VAR Framework
Granger causality is naturally tested within a Vector Autoregression (VAR) model.
Important Limitations
| Limitation | Explanation |
|-----------|------------|
| Predictive only | Tests statistical predictability, not mechanisms |
| Sensitive to lags | Results can change with different lag lengths |
| Linear only | Standard test assumes linear relationships |
| Stationarity | Series should be stationary or cointegrated |
| Omitted variables | May detect spurious causality if Z is missing |
Python Implementation
import numpy as np
import pandas as pd
from statsmodels.tsa.api import VAR
from statsmodels.tsa.stattools import grangercausalitytests
np.random.seed(42)
# Simulate correlated time series
n = 300
x = np.zeros(n)
y = np.zeros(n)
for t in range(1, n):
x[t] = 0.5 * x[t-1] + np.random.randn()
y[t] = 0.3 * x[t-1] + 0.4 * y[t-1] + np.random.randn()
data = pd.DataFrame({'Y': y, 'X': x})
# Granger causality test: X -> Y
print("X Granger-causes Y:")
gc_results = grangercausalitytests(data[['Y', 'X']], maxlag=5, verbose=True)
# VAR approach
model = VAR(data)
lag_order = model.select_order(maxlags=5)
print(f"\nSelected lag order: {lag_order.selected_orders['aic']}")
results = model.fit(maxlags=5)
print(results.summary())
Worked Example
Key Takeaways
Related Topics
-
See ARIMA Models for univariate time series modeling
-
See Causal Inference for methods that establish true causation
-
See Vector Autoregression for multivariate time series models