Hierarchical BVAR — R cross-check¶
Vector autoregressions, Part 7b¶
Validates bvarglp_python.ipynb. The BVAR package (Kuschnig & Vashold 2021) is an implementation of Giannone-Lenza-Primiceri (2015): it places hyperpriors on the Minnesota tightness $\lambda$ and the sum-of-coefficients / dummy-initial-observation hyperparameters and samples them via Metropolis-Hastings against the same closed-form marginal likelihood. If its hierarchical posterior for $\lambda$ lands in the same region as the from-scratch Python sampler, the marginal-likelihood machinery is corroborated across two independent implementations.
Data: bvecm_glp_data.csv — a 7-variable FRED-QD macro system in log-levels, quarterly 1959–2019 (McCracken & Ng, St. Louis Fed).
In [1]:
.libPaths('C:/Users/user/R/win-library/4.6')
suppressMessages(library(BVAR))
d <- read.csv('bvecm_glp_data.csv', row.names = 1)
# supply psi (per-series AR scale) directly; BVAR's automatic arima-based psi fails on this panel
psi_ar <- function(y, p = 4) { X <- embed(y, p + 1); var(resid(lm(X[, 1] ~ X[, -1]))) }
psi <- sapply(d, psi_ar); psi[!is.finite(psi) | psi <= 0] <- median(psi[is.finite(psi) & psi > 0])
pr <- bv_priors(mn = bv_mn(lambda = bv_lambda(), psi = bv_psi(mode = psi, min = psi/100, max = psi*100)),
soc = bv_soc(), sur = bv_sur())
set.seed(1)
f <- bvar(d, lags = 4, n_draw = 8000, n_burn = 4000, priors = pr, verbose = FALSE)
lam <- f$hyper[, 'lambda']
cat(sprintf('BVAR hierarchical posterior: lambda median %.3f [%.3f, %.3f]\n',
median(lam), quantile(lam, .16), quantile(lam, .84)))
cat(sprintf(' soc median %.3f | sur median %.3f\n', median(f$hyper[,'soc']), median(f$hyper[,'sur'])))
cat('cross-check -> Python (from-scratch GLP) lambda median ~0.29 : the two hierarchical samplers land in the same region.\n')
options(repr.plot.width = 7, repr.plot.height = 4)
plot(density(lam), col = 'firebrick', lwd = 2, main = 'Hierarchical posterior of the Minnesota tightness lambda',
xlab = expression(lambda))
abline(v = median(lam), col = 'firebrick', lty = 2)
abline(v = 0.2, col = 'navy', lty = 3, lwd = 2)
legend('topright', c('BVAR hierarchical posterior', 'fixed convention (0.2)'),
col = c('firebrick', 'navy'), lwd = 2, lty = c(1, 3), bty = 'n', cex = .85)
Warning message: "package 'BVAR' was built under R version 4.6.1"
BVAR hierarchical posterior: lambda median 0.301 [0.256, 0.329]
soc median 0.417 | sur median 0.842
cross-check -> Python (from-scratch GLP) lambda median ~0.29 : the two hierarchical samplers land in the same region.
The hierarchical estimate replicates¶
- Same data-driven tightness.
BVAR's marginal-likelihood posterior puts $\lambda$ at ~0.30 (median 0.301, 68% band [0.26, 0.33]) — close to the from-scratch Python sampler's ~0.29, and clearly to the right of the conventional fixed value 0.2, i.e. the data prefer less shrinkage than the default for this system. The package brings its own hyperprior defaults and a hand-supplied residual-variance scale, so this is an independent implementation landing in the same place, not a decimal-exact match. - The hyperparameters are genuinely uncertain. The posterior of $\lambda$ has real width; treating it as a single fixed number (as every earlier notebook did) discards that uncertainty — which is exactly what the density-forecast evaluation in the Python notebook shows to matter.
References¶
- Giannone, D., Lenza, M. & Primiceri, G. E. (2015). Prior selection for vector autoregressions. Review of Economics and Statistics 97, 436–451.
- Kuschnig, N. & Vashold, L. (2021). BVAR: Bayesian vector autoregressions with hierarchical prior selection in R. J. Statistical Software 100(14).