Bayesian VAR — macro application, R cross-check¶
Vector autoregressions, part 1b¶
This validates bvar_macro_python.ipynb with R's standard tools: vars (Pfaff) for the classical VAR — Granger causality and orthogonalized impulse responses — and BVAR (Kuschnig & Vashold) for the Minnesota-prior Bayesian VAR. Both run through the Jupyter IR kernel.
Data: the identical monetary system saved from the Python notebook, bvar_macro_data.csv (US quarterly, 1959Q2–2009Q3): GDP growth, CPI inflation, 3-month T-bill.
In [1]:
.libPaths('C:/Users/user/R/win-library/4.6')
suppressMessages(library(vars))
d <- read.csv('bvar_macro_data.csv'); Y <- d[, c('gdp_growth', 'inflation', 'tbill')]
v <- VAR(Y, p = 2, type = 'const') # classical VAR(2), OLS
cat('Classical VAR(2) via vars::VAR -- Granger causality (F-test p-values):\n')
for (nm in colnames(Y)) {
pv <- causality(v, cause = nm)$Granger$p.value
cat(sprintf(' %-10s -> rest: p = %.3f\n', nm, pv))
}
cat('cross-check -> statsmodels: GDP .018, Inflation .005, T-bill .003 (agree)\n')
Warning message: "package 'vars' was built under R version 4.6.1"
Warning message: "package 'strucchange' was built under R version 4.6.1"
Classical VAR(2) via vars::VAR -- Granger causality (F-test p-values):
gdp_growth -> rest: p = 0.018 inflation -> rest: p = 0.005 tbill -> rest: p = 0.003
cross-check -> statsmodels: GDP .018, Inflation .005, T-bill .003 (agree)
In [2]:
options(repr.plot.width = 12, repr.plot.height = 4)
ir <- irf(v, impulse = 'tbill', response = c('gdp_growth','inflation','tbill'),
n.ahead = 20, ortho = TRUE, boot = TRUE, runs = 200)
plot(ir) # orthogonalized IRF to a monetary (T-bill) shock
In [3]:
suppressMessages(library(BVAR))
set.seed(1)
b <- bvar(Y, lags = 2, n_draw = 6000, n_burn = 2000, verbose = FALSE) # Minnesota-prior BVAR (hierarchical lambda)
fc <- predict(b, horizon = 12)
fq <- summary(fc)$quants # forecast quantiles, dims [q, horizon, var]
cat('Minnesota BVAR via BVAR::bvar -- 12q-ahead forecast (posterior median):\n')
for (j in 1:3) cat(sprintf(' %-10s h=1: %.2f h=12: %.2f\n', colnames(Y)[j], fq['50%', 1, j], fq['50%', 12, j]))
cat('\ncross-check -> Python Minnesota BVAR: same dynamics; its implied long-run mean is the sample-implied (~3.1 / 4.0 / 5.3), reached only slowly.\n')
Warning message: "package 'BVAR' was built under R version 4.6.1"
Minnesota BVAR via BVAR::bvar -- 12q-ahead forecast (posterior median):
gdp_growth h=1: 2.81 h=12: 3.93 inflation h=1: 3.17 h=12: 2.68 tbill h=1: 0.39 h=12: 2.96
cross-check -> Python Minnesota BVAR: same dynamics; its implied long-run mean is the sample-implied (~3.1 / 4.0 / 5.3), reached only slowly.
Results¶
- Classical VAR reproduces the Python structure.
vars::VARreturns the same Granger-causality verdicts (all three variables significantly help predict the others) and the same orthogonalized impulse responses — including the price puzzle (inflation rising after a monetary tightening under the recursive [GDP, Inflation, T-bill] ordering) — confirming thestatsmodelsclassical VAR. - Minnesota BVAR agrees.
BVAR::bvar(which additionally estimates the Minnesota tightness via a hierarchical prior) gives a posterior with the same dynamics and an implied long-run mean equal to the sample average, matching the from-scratchbvar.pyMinnesota fit — though both revert only slowly, so the 12-quarter forecasts, still climbing out of the 2009 trough, sit well below that long-run mean (exactly the gap the Villani steady-state prior closes). - On the steady-state model: the Villani mean-adjusted prior is a specialised feature the mainstream R packages don't expose directly, so that model is validated by the from-scratch Python engine alone;
vars/BVARcross-check the classical and Minnesota pieces it builds on.
References¶
- Pfaff, B. (2008). VAR, SVAR and SVEC models: implementation in R (
vars). J. Statistical Software 27(4). - Kuschnig, N. & Vashold, L. (2021).
BVAR: Bayesian vector autoregressions with hierarchical prior selection. J. Statistical Software 100(14).