AR vs ADL vs VAR — Predicting Unemployment with Inflation

Author

AS

Published

April 25, 2026

The Two Questions, Answered Up Front

Q1. I want to predict unemployment using past unemployment only. Is this an ADL model?

No. That’s an AR(p) (or ARIMA) model. ADL — Auto-regressive Distributed Lag — requires lags of the dependent variable and lags of an external regressor. With only one variable, there is no “distributed lag” of anything outside.

Q2. I add inflation as a second variable to predict unemployment. Is this a VAR model?

Not necessarily. If you write one equation with \(U_t\) on the left and lags of \(U\) + lags of \(\pi\) on the right, that’s an ADL model. A VAR is a system: every variable appears on the LHS of its own equation, and every equation has lags of every variable on the RHS. ADL = one equation; VAR = a system of equations.

Model Equations LHS variables RHS (each equation)
AR(p) 1 \(U_t\) lags of \(U\)
ADL(p,q) 1 \(U_t\) lags of \(U\) + lags of \(\pi\)
VAR(p) 2 \((U_t, \pi_t)\) lags of \((U, \pi)\) in both equations

Compactly:

\[ \text{AR:}\quad U_t = c + \sum_{i=1}^{p} \phi_i U_{t-i} + \varepsilon_t \]

\[ \text{ADL:}\quad U_t = c + \sum_{i=1}^{p} \phi_i U_{t-i} + \sum_{j=1}^{q} \beta_j \pi_{t-j} + \varepsilon_t \]

\[ \text{VAR(p):}\quad \begin{bmatrix} U_t \\ \pi_t \end{bmatrix} = \mathbf{c} + \sum_{i=1}^{p} \begin{bmatrix} \phi_{11,i} & \phi_{12,i} \\ \phi_{21,i} & \phi_{22,i} \end{bmatrix} \begin{bmatrix} U_{t-i} \\ \pi_{t-i} \end{bmatrix} + \begin{bmatrix} \varepsilon_{1,t} \\ \varepsilon_{2,t} \end{bmatrix} \]

We will build all three on the same data and check whether adding inflation actually helps forecast unemployment out-of-sample.


Setup and Data

remove(list = ls())

library(fpp3)
library(dplyr)
library(tidyr)
library(ggplot2)
library(knitr)
library(fredr)

# Get a free FRED API key at https://fred.stlouisfed.org/docs/api/api_key.html
fredr_set_key("8a9ec1330374c1696f05cc8e526233b5")

Pull monthly unemployment rate (UNRATE) and the CPI (CPIAUCSL) from FRED, aggregate to quarters, and compute year-over-year inflation.

unrate_raw <- fredr(series_id = "UNRATE",
                    observation_start = as.Date("1960-01-01"))

cpi_raw    <- fredr(series_id = "CPIAUCSL",
                    observation_start = as.Date("1960-01-01"))

# Combine, aggregate to quarterly, compute YoY inflation.
# `obs_date` rename avoids any clash with base::date().
quarterly <- bind_rows(unrate_raw, cpi_raw) %>%
  rename(obs_date = date) %>%
  mutate(Quarter = yearquarter(obs_date)) %>%
  group_by(series_id, Quarter) %>%
  summarise(value = mean(value, na.rm = TRUE), .groups = "drop") %>%
  pivot_wider(names_from = series_id, values_from = value) %>%
  rename(Unemployment = UNRATE, CPI = CPIAUCSL) %>%
  mutate(Inflation = 100 * (CPI / lag(CPI, 4) - 1)) %>%   # YoY % change
  select(Quarter, Unemployment, Inflation) %>%
  drop_na() %>%
  as_tsibble(index = Quarter)

tail(quarterly)
quarterly %>%
  pivot_longer(c(Unemployment, Inflation), names_to = "Series", values_to = "Value") %>%
  autoplot(Value) +
  facet_wrap(~ Series, scales = "free_y", ncol = 1) +
  labs(
    title    = "U.S. Unemployment Rate and YoY CPI Inflation",
    subtitle = "Quarterly, FRED (UNRATE and CPIAUCSL)",
    x = NULL, y = "Percent"
  ) +
  theme_minimal()


Train / Test Split

We hold out the last 4 quarters and train on everything before. Using a 4-quarter horizon keeps the ADL forecast ex-ante valid: the inflation lags it needs (lag 1 to lag 4) all sit inside the training set when forecasting up to 4 quarters ahead.

h <- 4

# Pre-compute lagged inflation columns so they live in both train and test
df <- quarterly %>%
  mutate(
    Inflation_l1 = lag(Inflation, 1),
    Inflation_l2 = lag(Inflation, 2),
    Inflation_l3 = lag(Inflation, 3),
    Inflation_l4 = lag(Inflation, 4)
  ) %>%
  drop_na()

cutoff <- max(df$Quarter) - h
train  <- df %>% filter(Quarter <= cutoff)
test   <- df %>% filter(Quarter >  cutoff)

cat("Training: ", as.character(min(train$Quarter)), "to", as.character(max(train$Quarter)),
    "(", nrow(train), "quarters)\n")
Training:  1962 Q1 to 2025 Q1 ( 253 quarters)
cat("Test:     ", as.character(min(test$Quarter)),  "to", as.character(max(test$Quarter)),
    "(", nrow(test),  "quarters)\n")
Test:      2025 Q2 to 2026 Q1 ( 4 quarters)

Model 1 — AR(p) on Unemployment Alone

This is the AR / ARIMA answer to Q1. The model knows nothing about inflation; all signal must come from unemployment’s own past.

fit_ar <- train %>%
  model(AR = ARIMA(Unemployment))

report(fit_ar)
Series: Unemployment 
Model: ARIMA(1,0,0) w/ mean 

Coefficients:
         ar1  constant
      0.9092    0.5265
s.e.  0.0254    0.0427

sigma^2 estimated as 0.5015:  log likelihood=-271.57
AIC=549.14   AICc=549.23   BIC=559.74

Model 2 — ADL: Unemployment with Lagged Inflation

A single equation with \(U_t\) on the LHS and four lags of inflation on the RHS, plus the AR component (handled implicitly by ARIMA()). This is the ADL answer to Q2.

fit_adl <- train %>%
  model(
    ADL = ARIMA(Unemployment ~ Inflation_l1 + Inflation_l2 +
                                Inflation_l3 + Inflation_l4)
  )

report(fit_adl)
Series: Unemployment 
Model: LM w/ ARIMA(1,0,0) errors 

Coefficients:
         ar1  Inflation_l1  Inflation_l2  Inflation_l3  Inflation_l4  intercept
      0.9032       -0.0287        0.0340       -0.0156        0.0917     5.5022
s.e.  0.0266        0.0655        0.0703        0.0702        0.0657     0.5314

sigma^2 estimated as 0.5047:  log likelihood=-270.3
AIC=554.61   AICc=555.07   BIC=579.34

Model 3 — VAR: Joint System of Unemployment and Inflation

A system in which both unemployment and inflation are endogenous: each is regressed on lags of both. Notice we never wrote Inflation ~ ...VAR() does that for us.

fit_var <- train %>%
  model(
    VAR = VAR(vars(Unemployment, Inflation))
  )

report(fit_var)
Series: Unemployment, Inflation 
Model: VAR(5) w/ mean 

Coefficients for Unemployment:
      lag(Unemployment,1)  lag(Inflation,1)  lag(Unemployment,2)
                   0.8377           -0.0223               0.0387
s.e.               0.0672            0.0698               0.0875
      lag(Inflation,2)  lag(Unemployment,3)  lag(Inflation,3)
                0.0584               0.0640           -0.0413
s.e.            0.1135               0.0875            0.1157
      lag(Unemployment,4)  lag(Inflation,4)  lag(Unemployment,5)
                   0.0140            0.0673              -0.0635
s.e.               0.0878            0.1134               0.0662
      lag(Inflation,5)  constant
               -0.0100    0.4351
s.e.            0.0698    0.1840

Coefficients for Inflation:
      lag(Unemployment,1)  lag(Inflation,1)  lag(Unemployment,2)
                  -0.0256            1.3518              -0.0799
s.e.               0.0603            0.0627               0.0786
      lag(Inflation,2)  lag(Unemployment,3)  lag(Inflation,3)
               -0.3812               0.0940            0.2400
s.e.            0.1020               0.0786            0.1039
      lag(Unemployment,4)  lag(Inflation,4)  lag(Unemployment,5)
                   0.0787           -0.5937              -0.0795
s.e.               0.0788            0.1019               0.0595
      lag(Inflation,5)  constant
                0.3440    0.2295
s.e.            0.0627    0.1652

Residual covariance matrix:
             Unemployment Inflation
Unemployment       0.5042   -0.1314
Inflation         -0.1314    0.4068

log likelihood = -485.23
AIC = 1022.45   AICc = 1028.81  BIC = 1113.8

Forecast the Holdout Period

fc_ar  <- fit_ar  %>% forecast(h = h)
fc_adl <- fit_adl %>% forecast(new_data = test)   # needs lagged inflation in test
fc_var <- fit_var %>% forecast(h = h)

# For VAR, as_tibble() returns .mean as a matrix with one column per response.
# Pull out the Unemployment column by name and stack with AR / ADL forecasts.
var_fc_tbl <- as_tibble(fc_var)

fc_combined <- bind_rows(
  fc_ar  %>% as_tibble() %>% transmute(Quarter, .mean, Model = "AR"),
  fc_adl %>% as_tibble() %>% transmute(Quarter, .mean, Model = "ADL"),
  tibble(
    Quarter = var_fc_tbl$Quarter,
    .mean   = var_fc_tbl$.mean[, "Unemployment"],
    Model   = "VAR"
  )
)

ggplot(fc_combined, aes(x = Quarter, y = .mean, colour = Model)) +
  geom_line(linewidth = 1) +
  geom_line(data = test, aes(x = Quarter, y = Unemployment),
            inherit.aes = FALSE, colour = "black", linetype = "dashed") +
  labs(
    title    = "Out-of-Sample Forecasts of U.S. Unemployment",
    subtitle = "Dashed black = actual; coloured lines = each model",
    y = "Unemployment rate (%)", x = NULL
  ) +
  theme_minimal()


Accuracy Comparison

Now the punchline. Compute RMSE, MAE, MAPE, and MASE on the holdout, then compare across the three models.

acc_ar  <- fc_ar  %>%
  accuracy(test, measures = list(RMSE = RMSE, MAE = MAE, MAPE = MAPE, MASE = MASE)) %>%
  mutate(Model = "AR (univariate)")

acc_adl <- fc_adl %>%
  accuracy(test, measures = list(RMSE = RMSE, MAE = MAE, MAPE = MAPE, MASE = MASE)) %>%
  mutate(Model = "ADL (U + lagged Inflation)")

acc_var <- fc_var %>%
  accuracy(test, measures = list(RMSE = RMSE, MAE = MAE, MAPE = MAPE, MASE = MASE)) %>%
  filter(.response == "Unemployment") %>%
  mutate(Model = "VAR (joint U, Inflation)")

acc_table <- bind_rows(acc_ar, acc_adl, acc_var) %>%
  select(Model, RMSE, MAE, MAPE, MASE) %>%
  arrange(RMSE)

kable(
  acc_table,
  digits  = 3,
  caption = "Holdout Accuracy on the Last 4 Quarters of U.S. Unemployment"
)
Holdout Accuracy on the Last 4 Quarters of U.S. Unemployment
Model RMSE MAE MAPE MASE
VAR (joint U, Inflation) 0.142 0.117 2.710 NaN
ADL (U + lagged Inflation) 0.170 0.133 3.087 NaN
AR (univariate) 0.182 0.150 3.455 NaN
acc_table %>%
  pivot_longer(c(RMSE, MAE, MAPE, MASE), names_to = "Metric", values_to = "Value") %>%
  ggplot(aes(x = reorder(Model, Value), y = Value, fill = Model)) +
  geom_col(show.legend = FALSE) +
  coord_flip() +
  facet_wrap(~ Metric, scales = "free_x") +
  labs(
    title    = "Forecast Accuracy by Model and Metric",
    subtitle = "Lower is better — ADL and VAR add inflation; AR uses only unemployment's own past",
    x = NULL, y = NULL
  ) +
  theme_minimal()


Reading the Result

The intuition behind the comparison is straightforward:

  • AR treats unemployment as a closed system. Its only signal is the inertia in \(U_t\) itself. It will track persistence well but misses any leading information that lives elsewhere in the macro economy.
  • ADL lets the model “listen” to lagged inflation. To the extent that past inflation has any leading content for the next 4 quarters of unemployment (a Phillips-curve-style relationship), ADL captures it.
  • VAR goes one step further: it models inflation jointly with unemployment, so feedback in both directions is allowed. For a unidirectional forecast of unemployment, VAR and ADL are often close in accuracy; the bigger payoff from VAR shows up when you also need a coherent inflation forecast.

If the table above shows AR with the highest RMSE/MAE and ADL/VAR lower, that backs the intuition: adding inflation as a predictor improves out-of-sample forecasts of unemployment. If the gap is small (or AR wins narrowly), the honest reading is that over the holdout window the inflation signal was weak relative to the autoregressive inertia — a useful negative result to discuss with students.

TipTry It Yourself
  • Change h to 8 or 12 and rerun. Does ADL/VAR’s edge over AR grow or shrink at longer horizons?
  • Restrict the sample to a single regime (e.g., post-1985) by filtering quarterly. Does the inflation→unemployment signal change?
  • Replace YoY inflation with the quarter-over-quarter annualized rate. Does the noisier inflation series help or hurt?
  • Add the Fed Funds rate (FEDFUNDS from FRED) as a third variable and grow the VAR to 3 equations. Does the bigger system beat the 2-variable VAR?

Key Takeaways

  • AR / ARIMA uses only the variable’s own lags — one equation, one input series.
  • ADL is one equation but two input series: the dependent variable’s own lags + lags of an external regressor.
  • VAR is a system of equations, with every variable both endogenous and used as a predictor.
  • Choose AR when no external information is available; ADL when one regressor matters and only one variable needs forecasting; VAR when you need coherent forecasts of multiple variables that feed into each other.

References

  • Hyndman, R.J., & Athanasopoulos, G. (2021). Forecasting: Principles and Practice (3rd ed.), Chapters 10 (Dynamic regression) and 12.3 (Vector autoregressions). OTexts.
  • Stock, J.H., & Watson, M.W. (2001). Vector autoregressions. Journal of Economic Perspectives, 15(4), 101–115.