BVAR#
- class cultivars.multivariate.large_dim.bayesian.BVAR(endog, *, order, prior=None, trend='c', names=None)[source]
Bases:
_BayesianVectorAutoRegressionModel[BVARResult]Conjugate Normal-inverse-Wishart Bayesian VAR, after Banbura, Giannone and Reichlin.
The reduced-form vector autoregression
\[y_t = c + \sum_{l=1}^{p} A_l\, y_{t-l} + u_t, \qquad u_t \sim \mathcal{N}(0, \Sigma),\]estimated under a prior that makes the joint posterior over the coefficient matrix and the innovation covariance exact rather than sampled. Stacking the effective sample as \(Y = X B + U\), the prior is
\[\Sigma \sim \mathcal{IW}(S_0, \nu_0), \qquad \operatorname{vec}(B) \mid \Sigma \sim \mathcal{N}\bigl(\operatorname{vec}(B_0),\ \Sigma \otimes \Omega\bigr),\]with \(B_0\) centring each variable’s own first lag at
persistence(one, the random walk, by default) and every other coefficient at zero, \(\Omega\) diagonal with the Minnesota variance profile – tighter on longer lags, loose on the deterministic block – and \(S_0 = \operatorname{diag}(s_1^2, \ldots, s_k^2)\) with \(\nu_0 = k + 2\) built from univariate residual scales. The Kronecker form \(\Sigma \otimes \Omega\) is the whole point: it is exactly Litterman’s prior with the cross-equation weight pinned at one, and it is the condition for Normal-inverse-Wishart conjugacy, so the posterior is a closed-form update, its draws are independent, and its marginal likelihood has a closed form. What it gives up is Litterman’s claim that cross-variable coefficients deserve extra shrinkage. A prior that keeps that claim is refused rather than approximated, with directions to the point-estimate path that honours it.Shrinkage is what makes a large system estimable at all. With a proper prior the sample-length constraint is one observation per lag plus one, not one per regressor, so a system with more regressors than rows – routine at twenty or a hundred variables – fits here where
VARrefuses. The prior’s tightness, not the sample size, sets the effective number of parameters, which is why choosing it well matters and why the number this model reports for that choice is the marginal likelihood \(p(Y)\) rather than a likelihood or an information criterion: differences of its log across priors on the same sample are log Bayes factors, andHierarchicalBVARmaximizes it over the hyperparameters directly.Prior components compose with
+. The Doan-Litterman-Sims sum-of-coefficients and the Sims dummy-initial-observation priors are artificial rows \((Y_d, X_d)\) appended to the sample before the update, expressing beliefs about unit roots and cointegration on the scale of the presample means. They are part of the prior, so the fit reports the marginal likelihood of the sample given them, \(\log p(Y \mid Y_d)\), with the dummy rows’ own contribution divided out, and the number stays comparable across priors with and without dummies.- Parameters:
endog (
ArrayLike) – The observed panel, shape(nobs, k), time down the rows; anythingnumpy.asarray()accepts. A one-dimensional series is promoted to a single column. Must have more rows than columns and at leastorder + 2rows; beyond that, the regressor count imposes no constraint because the prior is proper.order (
int) – Autoregressive orderp, a positive integer. The Minnesota prior centres each variable’s own first lag, sop = 0has no prior to state and is refused. For choosing it,lag_order_selection()scores every order on one common sample.prior (
_Prior|None) – The prior to update under.NoneselectsNormalInverseWishartPriorat its defaults. A composition such asNormalInverseWishartPrior() + SumOfCoefficientsPrior() + DummyInitialObservationPrior()is accepted; the admissible components are listed below. Conjugacy is checked whenfit()runs, not here: a prior whose coefficient variances do not factor as \(\sigma_i^2 \cdot \omega_j\) is refused with aSpecificationErrorat that point.trend (
Literal['n','c','ct']) – Deterministic terms:"n"none,"c"a constant (default),"ct"a constant and a linear trend.names (
Sequence[str] |None) – One label per column ofendog, unique. Defaults toy1 ... yk. The order of the labels is the column order and, for orthogonalized impulse responses on the result, the recursive identifying ordering.
- Priors:
NormalInverseWishartPrior – The conjugate Minnesota prior and the default:
tightness,decay,exogenous, andpersistenceset \(\Omega\) and \(B_0\). Proper by construction, so it always carries a marginal likelihood.MinnesotaPrior – Accepted only with
cross_equation=1, where it is the same prior as above under Litterman’s parameterization. Any other cross-equation weight breaks the Kronecker factorization and is refused atfit(); pass it toVARinstead.SumOfCoefficientsPrior – A dummy-observation component,
kartificial rows, expressing that each variable’s own lags sum to one. Add it to a proper base prior; alone it is improper.DummyInitialObservationPrior – A dummy-observation component, one artificial row, expressing that the system starts at its presample mean. Add it to a proper base prior; alone it is improper.
- Raises:
SpecificationError – If
orderis not a positive integer, iftrendis not one of"n","c","ct", or ifnameshas the wrong length or repeats a label.DimensionError – If
endogis not two-dimensional after promotion, has no columns, has no more rows than columns, or has fewer thanorder + 1rows. The fit needs one row more, for the prior’s scales, and raises the same error when it is missing.NumericalError – If
endogcontains non-finite values.
Note
Construction validates the sample and the specification; the prior is validated when
fit()runs, because conjugacy is a property of the prior’s variances evaluated on this sample’s scales. A model can therefore be constructed with a prior it will later refuse.prior_replications()andprior_predictive_check()also evaluate the prior and raise the same error for an unusable one.Example
Fit under the default prior and read the posterior:
>>> import numpy as np >>> from cultivars.multivariate.large_dim.bayesian import BVAR >>> rng = np.random.default_rng(0) >>> y = np.zeros((120, 2)) >>> for t in range(1, 120): ... y[t] = 0.7 * y[t - 1] + rng.standard_normal(2) >>> res = BVAR(y, order=1, names=("growth", "inflation")).fit(n_draws=200, seed=0) >>> res.beta_draws.shape, res.n_dummy, res.posterior_df ((200, 3, 2), 0, 123.0)
A proper prior admits a system with more regressors than rows; twenty variables at two lags is 41 regressors per equation on 30 observations:
>>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR >>> wide = rng.standard_normal((30, 20)).cumsum(axis=0) >>> VAR(wide, order=2) Traceback (most recent call last): ... cultivars.exceptions.DimensionError: a sample of 30 rows is too short for VAR(2); ... >>> BVAR(wide, order=2).fit(n_draws=100, seed=0).beta_draws.shape (100, 41, 20)
Compose dummy observations onto the base prior and compare on the marginal likelihood of the same sample:
>>> from cultivars.bayes.priors import ( ... DummyInitialObservationPrior, ... NormalInverseWishartPrior, ... SumOfCoefficientsPrior, ... ) >>> prior = ( ... NormalInverseWishartPrior() ... + SumOfCoefficientsPrior() ... + DummyInitialObservationPrior() ... ) >>> dummies = BVAR(y, order=1, names=("growth", "inflation"), prior=prior) >>> res_d = dummies.fit(n_draws=200, seed=0) >>> res_d.n_dummy, res_d.prior_label (3, 'niw(l1=0.2, l3=1, l4=100) + soc(1) + dio(1)') >>> bool(res_d.log_marginal_likelihood > res.log_marginal_likelihood) True
A prior with Litterman’s cross-equation shrinkage is not conjugate and is refused when the fit runs:
>>> from cultivars.bayes.priors import MinnesotaPrior >>> model = BVAR(y, order=1, prior=MinnesotaPrior(cross_equation=0.5)) >>> model.fit(n_draws=10, seed=0) Traceback (most recent call last): ... cultivars.exceptions.SpecificationError: the prior variance does not factor as ...
The order is chosen on a common sample with the inherited information criteria:
>>> BVAR(y, order=1).lag_order_selection(4).selected["bic"] 1
See also
BVARResult– the fitted posterior, with the update formulas, the draws, and the propagating methods.HierarchicalBVAR– treats the tightnesses as unknowns and maximizes or integrates the marginal likelihood over them.GibbsBVAR– the independent Normal-Wishart prior, which drops the Kronecker restriction at the cost of a sampler.StudentBVARandBVARSV– heavy-tailed and stochastic-volatility innovations.VAR– the point-estimate path, which accepts aMinnesotaPriorwith cross-equation shrinkage as a per-equation ridge.prior_predictive_check()– what the prior deems plausible on the scale of the data, before any fit.
References
Litterman, R. B. (1986). Forecasting with Bayesian vector autoregressions: Five years of experience. Journal of Business & Economic Statistics, 4(1), 25-38.
Doan, T., Litterman, R., & Sims, C. (1984). Forecasting and conditional projection using realistic prior distributions. Econometric Reviews, 3(1), 1-100.
Sims, C. A. (1993). A nine-variable probabilistic macroeconomic forecasting model. In J. H. Stock & M. W. Watson (Eds.), Business Cycles, Indicators, and Forecasting (pp. 179-212). University of Chicago Press.
Kadiyala, K. R., & Karlsson, S. (1997). Numerical methods for estimation and inference in Bayesian VAR-models. Journal of Applied Econometrics, 12(2), 99-132.
Banbura, M., Giannone, D., & Reichlin, L. (2010). Large Bayesian vector auto regressions. Journal of Applied Econometrics, 25(1), 71-92.
Giannone, D., Lenza, M., & Primiceri, G. E. (2015). Prior selection for vector autoregressions. Review of Economics and Statistics, 97(2), 436-451.