🎉 75% of content is free forever — Unlock Premium from $10/mo →
CW
Search courses…
💼 Servicesℹ️ About✉️ ContactView Pricing Plansfrom $10

Granger Causality — Time Series Causality Testing

StatisticsTime Series Analysis🟢 Free Lesson

Advertisement

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.

DfGranger Causality

A time series XX Granger-causes YY if past values of XX contain information that improves the prediction of YY beyond what past values of YY alone provide.


Formal Definition

Consider forecasting YtY_t using its own past and the past of XX:

Restricted Model

Yt=α0+i=1pαiYti+εtY_t = \alpha_0 + \sum_{i=1}^{p}\alpha_i Y_{t-i} + \varepsilon_t

Here,

  • αi\alpha_i=Coefficient on lagged Y
  • pp=Number of lags
  • εt\varepsilon_t=Error term with variance $\sigma_1^2$

Unrestricted Model

Yt=α0+i=1pαiYti+j=1pβjXtj+εtY_t = \alpha_0 + \sum_{i=1}^{p}\alpha_i Y_{t-i} + \sum_{j=1}^{p}\beta_j X_{t-j} + \varepsilon_t

Here,

  • βj\beta_j=Coefficient on lagged X
  • εt\varepsilon_t=Error term with variance $\sigma_2^2$

Testing Granger Causality

If XX Granger-causes YY, then βj0\beta_j \neq 0 for at least one jj, and σ22<σ12\sigma_2^2 < \sigma_1^2.


Hypothesis Test

Granger Causality F-Test

F=(RSSrRSSur)/pRSSur/(T2p1)F = \frac{(\text{RSS}_r - \text{RSS}_{ur})/p}{\text{RSS}_{ur}/(T-2p-1)}

Here,

  • RSSrRSS_r=Residual sum of squares from restricted model
  • RSSurRSS_{ur}=Residual sum of squares from unrestricted model
  • pp=Number of lags tested
  • TT=Sample size

| Hypothesis | Conclusion |

|-----------|-----------|

| H0H_0: β1==βp=0\beta_1 = \cdots = \beta_p = 0 | XX does NOT Granger-cause YY |

| H1H_1: At least one βj0\beta_j \neq 0 | XX Granger-causes YY |


VAR Framework

Granger causality is naturally tested within a Vector Autoregression (VAR) model.

VAR(p) Model

[Yt Xt]=c+i=1pAi[Yti Xti]+[ε1t ε2t]\begin{bmatrix} Y_t \ X_t \end{bmatrix} = \mathbf{c} + \sum_{i=1}^{p}\mathbf{A}_i \begin{bmatrix} Y_{t-i} \ X_{t-i} \end{bmatrix} + \begin{bmatrix} \varepsilon_{1t} \ \varepsilon_{2t} \end{bmatrix}

Here,

  • Ai\mathbf{A}_i=2×2 coefficient matrix at lag i
  • c\mathbf{c}=Constant vector

Important Limitations

Granger Causality ? True Causality

Granger causality only tests predictive dependence, not true causal mechanisms. A significant result means:

  • XX is useful for forecasting YY

  • It does NOT mean XX causes YY

  • A third variable ZZ could cause both XX and YY

  • Results are sensitive to the lag length chosen

| 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

Example: GDP and Unemployment

Testing whether GDP growth Granger-causes changes in unemployment:

  1. ADF tests: Both series are non-stationary -> first differences are stationary

  2. VAR lag selection: AIC suggests 2 lags

  3. Granger test (H0H_0: GDP does not Granger-cause unemployment):

    • F-statistic = 8.32, p-value = 0.0003

    • Reject H0H_0: GDP growth helps predict unemployment changes

  4. Reverse test (H0H_0: Unemployment does not Granger-cause GDP):

    • F-statistic = 1.45, p-value = 0.236

    • Fail to reject H0H_0: Unemployment does not predict GDP

Conclusion: GDP Granger-causes unemployment, but not vice versa.


Key Takeaways

Summary: Granger Causality

  • Granger causality tests whether XX improves predictions of YY beyond YY's own past

  • It is a statistical test, not evidence of true causation

  • Test within a VAR framework using F-tests or likelihood ratio tests

  • Results depend on lag selection — always test multiple lag lengths

  • Both series should be stationary (or cointegrated if non-stationary)

  • Limitations: linear, predictive only, sensitive to omitted variables


Related Topics

Premium Content

Granger Causality — Time Series Causality Testing

Unlock this lesson and 900+ advanced tutorials with a Premium plan.

🎯End-to-end Projects
💼Interview Prep
📜Certificates
🤝Community Access

Already a member? Log in

Need Expert Statistics Help?

Get personalized tutoring, project support, or professional consulting.

Advertisement