BVARResult#

class cultivars.multivariate.large_dim.bayesian.BVARResult(*, endog, names, order, trend, prior_label, coefficients, deterministic, beta_mean, sigma_u, beta_draws, sigma_draws, log_marginal_likelihood, posterior_df, resid, fittedvalues, nobs, n_dummy)[source]

Bases: _SummaryMixin, _ConvergenceMixin, _ReplicationMixin

A fitted conjugate Bayesian VAR: an exact posterior over \((B, \Sigma)\).

The object BVAR.fit() returns. The posterior over the coefficient matrix and the innovation covariance is Normal-inverse-Wishart in closed form, so nothing here is approximated by a Markov chain: the S retained draws are independent samples from that posterior, point summaries are posterior means, and every method that propagates the system – irf(), irf_bands(), forecast(), forecast_paths(), posterior_replications(), and simulate() at a draw – propagates each draw separately. Their bands are therefore the posterior of the propagated object, not the propagation of a point.

The system is

\[y_t = c + \sum_{l=1}^{p} A_l\, y_{t-l} + u_t, \qquad u_t \sim \mathcal{N}(0, \Sigma),\]

stacked over the effective sample as \(Y = X B + U\) with \(Y\) of shape \((T - p) \times k\), \(X\) of shape \((T - p) \times w\), and \(B\) of shape \(w \times k\). The prior is the conjugate Minnesota form,

\[\Sigma \sim \mathcal{IW}(S_0, \nu_0), \qquad B \mid \Sigma \sim \mathcal{MN}(B_0,\, \Omega,\, \Sigma),\]

that is, \(\operatorname{vec}(B) \mid \Sigma \sim \mathcal{N}(\operatorname{vec}(B_0), \Sigma \otimes \Omega)\), with \(\nu_0 = k + 2\), \(S_0 = \operatorname{diag}(s_1^2, \ldots, s_k^2)\) built from the per-variable univariate residual scales, and \(\Omega\) the diagonal Minnesota variance profile with the cross-equation weight pinned at one. That Kronecker factorization is what makes the update exact:

\[K = \Omega^{-1} + X^\top X, \qquad \bar B = K^{-1}\left(\Omega^{-1} B_0 + X^\top Y\right),\]
\[\bar S = S_0 + Y^\top Y + B_0^\top \Omega^{-1} B_0 - \bar B^\top K \bar B, \qquad \bar\nu = \nu_0 + n,\]

where \(n\) counts every row updated on, sample and dummy rows together. Then \(\Sigma \mid Y \sim \mathcal{IW}(\bar S, \bar\nu)\) and \(B \mid \Sigma, Y \sim \mathcal{MN}(\bar B, K^{-1}, \Sigma)\). beta_mean is \(\bar B\), sigma_u is the exact posterior mean \(\bar S / (\bar\nu - k - 1)\), and posterior_df is \(\bar\nu\).

The scalar this result reports for model comparison is the log marginal likelihood, the matrix-variate-t normalizing-constant ratio in closed form,

\[\log p(Y) = -\tfrac{nk}{2}\log\pi - \tfrac{k}{2}\bigl(\log|K| + \log|\Omega|\bigr) + \tfrac{\nu_0}{2}\log|S_0| - \tfrac{\bar\nu}{2}\log|\bar S| + \log\Gamma_k\!\bigl(\tfrac{\bar\nu}{2}\bigr) - \log\Gamma_k\!\bigl(\tfrac{\nu_0}{2}\bigr).\]

When the prior contributes dummy observations \(Y_d\) (a sum-of-coefficients or dummy-initial-observation component), they are part of the prior, not of the sample, so log_marginal_likelihood is \(\log p(Y \mid Y_d) = \log p(Y, Y_d) - \log p(Y_d)\). That makes the number comparable across priors with different dummy content: differences across priors on the same sample are log Bayes factors, and the hierarchical layer, HierarchicalBVAR, chooses hyperparameters by maximizing it.

Deliberately absent: llf, n_params, and information criteria. A posterior has none of them, and the marginal likelihood is the honest replacement.

Shapes:
  • T – Rows of endog. The first p rows are the presample the fit conditions on.

  • p – Autoregressive order, order.

  • k – Endogenous variables, k_endog.

  • n_det – Deterministic regressors per equation: 0, 1, or 2 for trend "n", "c", or "ct".

  • w – Regressors per equation, n_det + k * p.

  • S – Retained posterior draws, n_kept.

Variables:
  • endog – The observed panel, (T, k), including the presample.

  • names – Variable labels in column order. Their order is also the recursive ordering behind every orthogonalized impulse response.

  • order – Autoregressive order p.

  • trend – Deterministic specification, one of "n", "c", "ct".

  • prior_label – Short description of the prior the posterior was updated under, as it appears in the summary and in comparison tables.

  • coefficients – (p, k, k) lag stack at the posterior mean: coefficients[l - 1] is \(A_l\), and its [i, j] entry is the response of equation i to variable j at lag l. Each slice is the transpose of the corresponding lag block of beta_mean.

  • deterministic – (n_det, k) deterministic block at the posterior mean: the constant row, then the trend row when present.

  • beta_mean – (w, k) posterior mean \(\bar B\) in design-row order: the deterministic rows first, then the lag blocks lag-major, so row n_det + (l - 1) * k + j carries variable j at lag l; columns index equations. The row labels credible_interval() accepts are "const", "trend", and "{name}.L{lag}".

  • sigma_u – (k, k) exact posterior mean of the innovation covariance, \(\bar S / (\bar\nu - k - 1)\); not the average of sigma_draws, which converges to it.

  • beta_draws – (S, w, k) independent coefficient draws, laid out as beta_mean.

  • sigma_draws – (S, k, k) independent covariance draws, paired with beta_draws draw by draw.

  • log_marginal_likelihood – Log marginal likelihood of the sample given the prior, dummy-observation content divided out.

  • posterior_df – Inverse-Wishart posterior degrees of freedom \(\bar\nu = k + 2 + \text{nobs} + \text{n\_dummy}\).

  • resid – (nobs, k) residuals at the posterior mean, aligned with endog[p:].

  • fittedvalues – (nobs, k) one-step-ahead means at the posterior mean, aligned with endog[p:].

  • nobs – Effective sample size T - p; dummy rows excluded.

  • n_dummy – Artificial rows the prior contributed to the update.

Note

Every three-number summary on this result – credible_interval(), irf_bands(), forecast() – is (16th percentile, mean, 84th percentile) taken pointwise across the draws: a 68% central credible band, one standard deviation wide under normality. Take other quantiles from beta_draws, sigma_draws, or forecast_paths() directly.

The draws are independent, so convergence() exists for interface parity with the Gibbs-sampled members of the family rather than as a diagnostic: R-hat is one by construction, and an effective-sample flag means only that n_draws was small.

Warning

Orthogonalized responses rotate each draw by its own Cholesky factor, so the order of names is an identifying assumption exactly as in a recursive SVAR. Reorder the columns of endog before fitting to change it.

Example

Simulate a stable bivariate system, fit it, 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.sigma_draws.shape
((200, 3, 2), (200, 2, 2))
>>> res.nobs, res.n_dummy, res.posterior_df
(119, 0, 123.0)
>>> low, mean, high = res.credible_interval("growth", "growth.L1")
>>> bool(low < mean < high)
True
>>> res.stable_share
1.0

Propagation is draw by draw, so the bands are posterior bands of the propagated object:

>>> res.irf_bands(8).shape
(9, 2, 2, 3)
>>> res.forecast(4).shape
(4, 2, 3)
>>> res.forecast_paths(4, seed=0).shape
(200, 4, 2)

Rank priors on the same sample by log marginal likelihood; the difference is a log Bayes factor:

>>> from cultivars.bayes.evidence import compare
>>> from cultivars.bayes.priors import NormalInverseWishartPrior
>>> tight = NormalInverseWishartPrior(tightness=0.02)
>>> alt = BVAR(y, order=1, names=("growth", "inflation"), prior=tight)
>>> alt = alt.fit(n_draws=200, seed=0)
>>> round(res.log_marginal_likelihood - alt.log_marginal_likelihood, 1)
6.1
>>> compare(res.marginal_likelihood(), alt.marginal_likelihood()).rows[0][0]
'BVAR(1), niw(l1=0.2, l3=1, l4=100)'

See also

  • BVAR – the model whose fit() produces this result.

  • HierarchicalBVAR – treats the prior tightnesses as unknowns and integrates over them.

  • GibbsBVAR – the same system under an independent Normal-Wishart prior, sampled rather than exact.

  • StudentBVAR and BVARSV – heavy-tailed and stochastic-volatility members of the family.

  • VAR – the point-estimate path, which also accepts a MinnesotaPrior with cross-equation shrinkage.

  • compare() – ranks marginal_likelihood() records across models.

  • posterior_predictive_check() – scores posterior_replications() against observed.

  • fan_chart() – draws forecast_paths() as a fan.

References

Litterman, R. B. (1986). Forecasting with Bayesian vector autoregressions: Five years of experience. Journal of Business & Economic Statistics, 4(1), 25-38.

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.

Karlsson, S. (2013). Forecasting with Bayesian vector autoregression. In G. Elliott & A. Timmermann (Eds.), Handbook of Economic Forecasting (Vol. 2A, pp. 791-897). Elsevier.

Private attributes#

_n_deterministic

0, 1, or 2.

Private methods#

_from_fit(fit, model)

Assemble the public result from a raw fit and the model that produced it.

_irf_draws(horizon, *, orthogonalized)

Impulse responses of every retained draw, (S, horizon + 1, k, k).

_regressor_labels()

Per-equation regressor labels, in design-row order.

_stack_of(beta)

Slice one (w, k) coefficient matrix into its (p, k, k) lag stack.

_summary_table()

Build the structured summary every renderer draws from.