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]#

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.

Attributes#

endog

The observed panel, (T, k), including the presample.

names

Variable labels, one per column of endog, in column order.

order

the number of lag blocks in coefficients.

trend

"n" (none), "c" (constant), or "ct".

prior_label

Short description of the prior the posterior was updated under.

coefficients

(p, k, k) lag stack at the posterior mean.

deterministic

(n_det, k) deterministic block at the posterior mean.

beta_mean

(w, k) posterior mean coefficient matrix \(\bar B\).

sigma_u

(k, k) exact posterior mean of the innovation covariance.

beta_draws

(S, w, k) independent posterior draws of the coefficient matrix.

sigma_draws

(S, k, k) independent posterior draws of the innovation covariance.

log_marginal_likelihood

Log marginal likelihood of the sample given the prior, in closed form.

posterior_df

Inverse-Wishart posterior degrees of freedom \(\bar\nu\).

resid

(nobs, k) residuals at the posterior mean.

fittedvalues

(nobs, k) one-step-ahead conditional means at the posterior mean.

nobs

the rows the posterior was updated on, dummy rows excluded.

n_dummy

Artificial rows the prior contributed to the update.

k_endog

Number of endogenous variables, k.

n_kept

Posterior draws retained, S.

observed

The effective sample the replications are shaped like, (nobs, k).

stable_share

Posterior probability that the system is stable.

Methods#

convergence(*chains[, include, exclude, ...])

Assess the sampler's convergence over the retained draws.

credible_interval(equation, regressor)

Posterior summary of one coefficient: 16th percentile, mean, 84th percentile.

forecast([steps, seed])

The posterior predictive: parameter and shock uncertainty.

forecast_paths([steps, seed])

The posterior predictive's raw simulated paths, one per retained draw.

irf([horizon, orthogonalized, cumulative])

Posterior mean impulse responses.

irf_bands([horizon, orthogonalized, cumulative])

Posterior bands of the impulse responses.

marginal_likelihood()

The closed-form log marginal likelihood as a comparable record.

posterior_replications([n_replications, seed])

Replicated effective samples, one per posterior draw used.

simulate([n, seed, burn, draw])

A fresh sample path from the fitted system at the posterior mean or at one draw.

summary()

The estimation summary, renderable as text, HTML, or a dataframe.