A Practical Guide with R
2026-09-12
Recall from Johansen Method:
Example: \[Y_t = \beta_0 + \beta_1 X_t + u_t\]
If \(Y_t \sim I(1)\) and \(X_t \sim I(1)\), but \(u_t \sim I(0)\), then \(Y\) and \(X\) are cointegrated.
Note
Cointegration prevents spurious regression problems!
You already know Johansen cointegration requires:
Important
Question: What if some variables are I(0) and others are I(1)?
Answer: This is where ARDL comes in!
AutoRegressive Distributed Lag Model
General form with one dependent and one independent variable:
\[Y_t = \alpha_0 + \sum_{i=1}^{p}\beta_i Y_{t-i} + \sum_{j=0}^{q}\gamma_j X_{t-j} + \varepsilon_t\]
Flexibility in modeling dynamic relationships:
Tip
ARDL is particularly useful for macroeconomic data where relationships have both immediate and lagged effects.
With multiple independent variables:
\[Y_t = \alpha_0 + \sum_{i=1}^{p}\beta_i Y_{t-i} + \sum_{j=0}^{q_1}\gamma_{1j} X_{1,t-j} + \sum_{j=0}^{q_2}\gamma_{2j} X_{2,t-j} + \sum_{j=0}^{q_3}\gamma_{3j} X_{3,t-j} + \varepsilon_t\]
The PSS (2001) Bounds Testing Approach
Warning
Important restriction: Variables cannot be I(2) or higher!
You still need to check this.
Two-step transformation:
Step 1: Original ARDL model in levels
Step 2: Transform to Error Correction Model (ECM) representation
\[\Delta Y_t = \beta_0 + \sum_{i=1}^{p-1}\beta_i \Delta Y_{t-i} + \sum_{j=0}^{q-1}\gamma_j \Delta X_{t-j} + \underbrace{\theta_0 Y_{t-1} + \theta_1 X_{t-1}}_{\text{Long-run relationship}} + \varepsilon_t\]
Note
The lagged level terms (\(Y_{t-1}, X_{t-1}\)) capture the long-run relationship!
Hypothesis Testing:
\[H_0: \theta_0 = \theta_1 = 0 \quad \text{(No cointegration)}\] \[H_1: \theta_0 \neq 0 \text{ or } \theta_1 \neq 0 \quad \text{(Cointegration exists)}\]
Test using F-statistic (or Wald test)
Compare your F-statistic with critical value bounds:
PSS (2001) provide tables based on:
Example critical values at 5% level (k=3, n=large):
| Bound Type | Critical Value |
|---|---|
| I(0) | 3.23 |
| I(1) | 4.35 |
Tip
Modern R packages calculate these automatically!
Step 1: Check Order of Integration
Step 2: Estimate ARDL Model
Step 3: Bounds Test
Step 4: If Cointegration Exists
Estimate the long-run relationship:
\[Y_t = \beta_0 + \beta_1 X_{1,t} + \beta_2 X_{2,t} + \beta_3 X_{3,t} + u_t\]
Step 5: Error Correction Model (ECM)
\[\Delta Y_t = \text{short-run dynamics} + \delta \cdot ECT_{t-1} + \varepsilon_t\]
Where \(ECT_{t-1} = Y_{t-1} - \hat{\beta}_0 - \hat{\beta}_1 X_{1,t-1} - \hat{\beta}_2 X_{2,t-1} - \hat{\beta}_3 X_{3,t-1}\)
Important
\(\delta\) should be negative and significant for valid cointegration!
Let’s use a practical example: Relationship between Consumption, Income, and Interest Rate
# Example with simulated data (replace with your real data)
set.seed(123)
n <- 100
# Create time series
time <- 1:n
income <- 100 + 0.5*time + cumsum(rnorm(n, 0, 2))
interest <- 5 + 0.01*time + rnorm(n, 0, 0.5)
consumption <- 20 + 0.7*income - 2*interest + rnorm(n, 0, 3)
# Create data frame
data <- data.frame(
time = time,
consumption = consumption,
income = income,
interest = interest
)
head(data)Check that no variables are I(2):
# ADF test function
adf_test <- function(x) {
test <- ur.df(x, type = "trend", lags = 4)
return(test@teststat[1])
}
# Test levels
cat("ADF Test - Levels:\n")
cat("Consumption:", adf_test(data$consumption), "\n")
cat("Income:", adf_test(data$income), "\n")
cat("Interest:", adf_test(data$interest), "\n")
# Test first differences
cat("\nADF Test - First Differences:\n")
cat("D.Consumption:", adf_test(diff(data$consumption)), "\n")
cat("D.Income:", adf_test(diff(data$income)), "\n")
cat("D.Interest:", adf_test(diff(data$interest)), "\n")Note
Critical value at 5%: approximately -3.45 (with trend)
# Auto-select lags using AIC
ardl_model <- auto_ardl(
consumption ~ income + interest,
data = data,
max_order = 5, # Maximum lag to consider
selection = "AIC" # Can also use "BIC"
)
# View selected model
summary(ardl_model)
# Get the selected lag order
ardl_model$order
# Output example: (2, 1, 3) means ARDL(2,1,3)Tip
AIC (Akaike) - better for prediction
BIC (Schwarz) - more parsimonious, better for small samples
Interpretation:
If cointegration is confirmed:
Output interpretation:
Key checks:
Always check model validity:
# 1. Serial Correlation Test
bg_test <- bgtest(ardl_model, order = 4)
print(bg_test)
# 2. Heteroskedasticity Test
bp_test <- bptest(ardl_model)
print(bp_test)
# 3. Normality Test
jb_test <- jarque.bera.test(residuals(ardl_model))
print(jb_test)
# 4. Stability Test (CUSUM)
plot(stability(ardl_model, type = "cusum"))Warning
If diagnostics fail, consider:
- Adding more lags
- Including dummy variables
- Transforming variables (log)
Short-Run Coefficients (from ARDL/ECM):
Long-Run Coefficients:
Example: \(ECT_{t-1} = -0.35\) (p-value < 0.01)
Interpretation:
Important
If ECT > 0 or insignificant, the cointegration relationship is questionable!
# Plot actual vs fitted values
plot(ardl_model)
# Plot residuals
residuals_df <- data.frame(
time = 1:length(residuals(ardl_model)),
residuals = residuals(ardl_model)
)
ggplot(residuals_df, aes(x = time, y = residuals)) +
geom_line() +
geom_hline(yintercept = 0, color = "red", linetype = "dashed") +
labs(title = "ARDL Model Residuals",
x = "Time", y = "Residuals") +
theme_minimal()
# Plot dynamic forecasts
forecast_plot <- forecast(ardl_model, h = 10)
plot(forecast_plot)| Feature | ARDL Bounds Test | Johansen Method |
|---|---|---|
| Order of integration | I(0), I(1), or mixed | All must be I(1) |
| Pre-testing required | No (only check not I(2)) | Yes (must confirm I(1)) |
| Estimation | Single equation | System (VAR) |
| Complexity | Simpler | More complex |
| Small samples | Works well (n≥30) | Needs larger samples |
| Different lags | Yes, per variable | No, same for all |
| Endogeneity | Can handle with lags | Better for simultaneous equations |
ARDL is preferred when:
Johansen is preferred when:
Note
Many researchers use both methods as robustness checks!
Let’s analyze the relationship between GDP, Investment, and Government Spending using Pakistani data:
# Load data (example - use your own data)
library(readr)
pak_data <- read_csv("pakistan_macro.csv")
# Variables:
# - gdp: Real GDP (in billions)
# - investment: Gross Fixed Capital Formation
# - govt_spending: Government Expenditure
# Take logs for elasticity interpretation
pak_data <- pak_data %>%
mutate(
log_gdp = log(gdp),
log_inv = log(investment),
log_govt = log(govt_spending)
)library(urca)
# ADF tests on levels
adf_gdp <- ur.df(pak_data$log_gdp, type = "trend", lags = 4)
adf_inv <- ur.df(pak_data$log_inv, type = "trend", lags = 4)
adf_govt <- ur.df(pak_data$log_govt, type = "trend", lags = 4)
# Summary
summary(adf_gdp)
summary(adf_inv)
summary(adf_govt)
# Check first differences if needed
adf_d_gdp <- ur.df(diff(pak_data$log_gdp), type = "trend", lags = 4)
summary(adf_d_gdp)Expected result: Variables are I(1), good for ARDL!
Interpretation: F = 5.234 > Upper bound at 5% (4.35)
→ Strong evidence of cointegration!
Economic Interpretation:
Interpretation:
# Load required package
library(lmtest)
# 1. Breusch-Godfrey Test (Serial Correlation)
bgtest(ardl_pak, order = 4)
# H0: No serial correlation
# 2. Breusch-Pagan Test (Heteroskedasticity)
bptest(ardl_pak)
# H0: Homoskedastic errors
# 3. Jarque-Bera Test (Normality)
jarque.bera.test(residuals(ardl_pak))
# H0: Errors are normally distributed
# 4. CUSUM Test (Stability)
cusum_test <- stability(ardl_pak, type = "cusum")
plot(cusum_test)# Plot actual vs fitted
library(ggplot2)
fitted_vals <- fitted(ardl_pak)
actual_vals <- pak_data$log_gdp[1:length(fitted_vals)]
plot_df <- data.frame(
time = 1:length(actual_vals),
actual = actual_vals,
fitted = fitted_vals
)
ggplot(plot_df, aes(x = time)) +
geom_line(aes(y = actual, color = "Actual"), size = 1) +
geom_line(aes(y = fitted, color = "Fitted"), size = 1, linetype = "dashed") +
labs(title = "ARDL Model: Actual vs Fitted Values",
subtitle = "Log GDP in Pakistan",
x = "Time Period", y = "Log GDP",
color = "Series") +
theme_minimal() +
theme(legend.position = "bottom")If you suspect structural breaks (e.g., policy changes, crises):
Include squared terms for non-linear relationships:
Test for non-linearity: If \(\beta_{inv^2}\) is significant, relationship is non-linear
Account for asymmetric effects (positive vs negative changes):
Note
NARDL is useful when effects differ in expansions vs recessions
In your paper/thesis, report:
Tip
Create a comprehensive table with all results for easy reference!
Key Takeaways:
Quick Decision Guide:
flowchart TD
A[Start: Check Your Data] --> B{Variables <br/> mixed I0/I1?}
B -->|Yes| C[Use ARDL]
B -->|No, All I1| D{Small sample <br/> n < 80?}
D -->|Yes| C
D -->|No| E{Single equation <br/> focus?}
E -->|Yes| F[ARDL preferred <br/> Simpler]
E -->|No| G{Multiple <br/> cointegrating <br/> relations?}
G -->|Yes| H[Use Johansen]
G -->|No| F
style C fill:#90EE90
style H fill:#FFB6C1
style F fill:#90EE90
C --> I[ARDL Bounds Test]
H --> J[Johansen Test]
F --> K[Either works <br/> Use both for robustness]flowchart TD
A[Start: Check Your Data] --> B{Variables <br/> mixed I0/I1?}
B -->|Yes| C[Use ARDL]
B -->|No, All I1| D{Small sample <br/> n < 80?}
D -->|Yes| C
D -->|No| E{Single equation <br/> focus?}
E -->|Yes| F[ARDL preferred <br/> Simpler]
E -->|No| G{Multiple <br/> cointegrating <br/> relations?}
G -->|Yes| H[Use Johansen]
G -->|No| F
style C fill:#90EE90
style H fill:#FFB6C1
style F fill:#90EE90
C --> I[ARDL Bounds Test]
H --> J[Johansen Test]
F --> K[Either works <br/> Use both for robustness]
Key Decision Points:
Tip
Best Practice: Use both methods as robustness checks when possible!
Essential packages:
# ARDL analysis
install.packages("ARDL") # Main package
install.packages("dynamac") # Alternative
# Unit root tests
install.packages("urca") # Comprehensive tests
install.packages("tseries") # ADF, PP, KPSS
# Diagnostics
install.packages("lmtest") # LM tests
install.packages("car") # VIF, other tests
# Visualization
install.packages("ggplot2") # Publication-quality plotsKey Papers:
Pesaran, M. H., Shin, Y., & Smith, R. J. (2001). Bounds testing approaches to the analysis of level relationships. Journal of Applied Econometrics, 16(3), 289-326.
Pesaran, M. H., & Shin, Y. (1999). An autoregressive distributed lag modelling approach to cointegration analysis.
Online Resources:
help(package = "ARDL")Try this on your own:
auto_ardl()Tip
Start with Pakistani data from World Bank or State Bank of Pakistan!
Thank you!
Contact:
Remember:
Practice makes perfect. Start with simple examples and gradually increase complexity!
Pesaran, M. H., Shin, Y., & Smith, R. J. (2001). Bounds testing approaches to the analysis of level relationships. Journal of Applied Econometrics, 16(3), 289-326.
Pesaran, M. H., & Shin, Y. (1999). An autoregressive distributed lag modelling approach to cointegration analysis. Econometrics and Economic Theory in the 20th Century: The Ragnar Frisch Centennial Symposium, 371-413.
Nkoro, E., & Uko, A. K. (2016). Autoregressive Distributed Lag (ARDL) cointegration technique: application and interpretation. Journal of Statistical and Econometric Methods, 5(4), 63-91.
Jordan, S., & Philips, A. Q. (2018). Cointegration testing and dynamic simulations of autoregressive distributed lag models. The Stata Journal, 18(4), 902-923.