Skip to content

Models

The sampling model determines both the prior specification and the estimation algorithm. Every model is a subclass of SamplingModel and owns the complete estimation pipeline — prior construction, data-matrix assembly, dummy-observation stacking, and posterior sampling.

Selecting a Model

Model Prior structure Estimation Marginal likelihood
NaturalConjugate \(\text{vec}(A) \mid \Sigma \sim \mathcal{N}(\beta_0,\, \Sigma \otimes V_A^{-1})\), \(\Sigma \sim \mathcal{IW}(S_0, \nu_0)\) Direct (no MCMC) ✔
IndependentNIW \(\beta \sim \mathcal{N}(\beta_0, V_\beta)\) independently of \(\Sigma \sim \mathcal{IW}(S_0, \nu_0)\) Gibbs sampler ✘

The Marginal likelihood column indicates whether optimise_hyperparameters with optimisation_method="ml" is supported. IndependentNIW (✘) has no closed-form marginal likelihood, and its Gibbs sampler has no closed-form point estimate, so neither "ml" nor "cross_validation" is available for it — passing either raises ValueError. Use optimisation_method="none" and set hyperparameters manually.

Use NaturalConjugate for most applications: it runs faster without burn-in, supports marginal-likelihood hyperparameter optimisation, and covers the standard Minnesota / SOC / SUR prior setup. Use IndependentNIW when you need a full \((nk \times nk)\) prior precision matrix that scales cross-variable shrinkage independently of \(\Sigma\).

Usage

import bvar as bv

# Natural conjugate (fast, supports ML optimisation)
model = bv.NaturalConjugate(
    minnesota=True,
    soc=True,
    sur=True,
    covid=False,
)

bvar = bv.BVAR(n_lags=4, model=model, stationary=False)
bvar.optimise_hyperparameters(data)
bvar.sample(data, N_draws=5000)
# Independent NIW (full-system prior precision, Gibbs sampler)
model = bv.IndependentNIW(
    c2=0.5,  # cross-variable shrinkage
    minnesota=True,
    soc=False,
    sur=False,
)

bvar = bv.BVAR(n_lags=4, model=model, stationary=False, optimisation_method="none")
bvar.sample(data, N_draws=5000)

Base Class

bvar.models.SamplingModel

SamplingModel(minnesota: bool = True, soc: bool = True, sur: bool = True, covid: bool = False, covid_dates: Optional[list] = None)

Abstract base class for BVAR estimation models.

Each subclass owns the entire estimation pipeline and the prior hyperparameters that drive it. Common prior flags (minnesota, soc, sur, covid) and the shared hyperparameter infrastructure live here; subclasses add model-specific parameters.

PARAMETER DESCRIPTION
minnesota

Apply Minnesota shrinkage to the coefficient prior. Default True; with False the coefficient prior is effectively flat.

TYPE: bool DEFAULT: True

soc

Add sum-of-coefficients dummy observations. Default True. Disabled for a fit when stationary=True is passed to BVAR.

TYPE: bool DEFAULT: True

sur

Add a single-unit-root dummy observation. Default True. Disabled for a fit when stationary=True is passed to BVAR.

TYPE: bool DEFAULT: True

covid

Include COVID-19 outlier dummies. Default False.

TYPE: bool DEFAULT: False

covid_dates

Two-element list [start, end] defining the COVID period. Each element may be anything pandas can interpret as a date (e.g. a string "2020-03-01", a pd.Timestamp or a pd.Period). The method matches dates against the data index at the data's own frequency, so it supports monthly, quarterly, and other frequencies. Defaults to the 2020Q1-2021Q4 window if None.

TYPE: Optional[list] DEFAULT: None

ATTRIBUTE DESCRIPTION
requires_burnin

True for MCMC samplers whose initial draws should be discarded; False for direct samplers.

TYPE: bool

supports_ml

True if a closed-form marginal likelihood is available for hyperparameter optimisation (GLP 2015).

TYPE: bool

supports_point_only

True if the model has a closed-form posterior point estimate and supports point_only=True sampling. Required for optimisation_method="cross_validation", which repeatedly refits the model with point_only=True inside the grid search.

TYPE: bool

supports_gaussian_predictive

True when the model uses the reduced-form Gaussian used by :meth:sample_innovations, :meth:sample_conditional_forecast and :meth:predictive_logpdf. True for every current (Gaussian) model. A non-Gaussian model should set this to False and override each hook that needs a different predictive distribution; the default implementations raise NotImplementedError in that case.

TYPE: bool

supports_girf

True if :meth:~bvar.girf.GIRF.compute_girf may be used with this model. True for every current (Gaussian) model. The current GIRF implementation is hard-coded to the Gaussian reduced-form predictive distribution, so compute_girf also requires supports_gaussian_predictive=True; setting supports_girf=True on a model with supports_gaussian_predictive=False does not enable GIRFs. A non-Gaussian model should leave this False until a GIRF implementation compatible with its own predictive distribution exists.

TYPE: bool

set_priors

set_priors(c1: float = 0.2, c3: float = 2.0, lambda_constant: float = 10.0, mu: float = 1.0, theta: float = 1.0, lambda_covid: float = 10000.0, c1_mode: float = 0.2, c1_sd: float = 0.4, c3_mode: float = 2.0, c3_sd: float = 0.5, mu_mode: float = 1.0, mu_sd: float = 1.0, theta_mode: float = 1.0, theta_sd: float = 1.0) -> None

Set prior hyperparameters.

Subclasses may override to accept model-specific parameters (e.g. c2 for :class:IndependentNIW).

fill_in_from_vector

fill_in_from_vector(pars: ndarray) -> None

Update hyperparameters from an optimisation vector.

The vector layout is [c1, c3, ...] followed by mu (if SOC) and theta (if SUR). Subclasses may override to insert model-specific hyperparameters.

to_vector

to_vector() -> ndarray

Extract searchable hyperparameters as a vector.

hyperparameter_grid

hyperparameter_grid() -> list[ndarray]

Return default grid arrays for cross-validation.

The order matches :meth:fill_in_from_vector.

sample abstractmethod

sample(data: ndarray, n_lags: int, covid_indices: ndarray, vars_in_levels: ndarray, N_draws: int, point_only: bool = False, progressbar: bool = True, soc: Optional[bool] = None, sur: Optional[bool] = None, rng: Optional[Generator] = None) -> SamplingResult

Run the full estimation pipeline and return posterior draws.

During estimation, store the prior mean (self.beta_0) and prior precision (self.V_A_inv) so that :meth:sample_posterior_state can reuse them.

PARAMETER DESCRIPTION
data

Raw data array with shape (T_total, n) (before lag trimming).

TYPE: ndarray

n_lags

Number of VAR lags.

TYPE: int

covid_indices

Observation indices for COVID dummy variables.

TYPE: ndarray

vars_in_levels

Boolean array with shape (n,) indicating which variables are in levels.

TYPE: ndarray

N_draws

Total number of posterior draws to generate, including draws that the caller will discard as burn-in.

TYPE: int

point_only

If True, compute only the posterior point estimate.

TYPE: bool DEFAULT: False

progressbar

Whether to display a progress bar.

TYPE: bool DEFAULT: True

soc

Effective sum-of-coefficients flag for this fit. The flag records whether the code stacks SOC dummy observations. It defaults to self.soc; callers should pass a fit-specific value, such as False when no variable uses levels, rather than mutate self.soc.

TYPE: Optional[bool] DEFAULT: None

sur

Effective single-unit-root flag for this fit, analogous to soc. Defaults to self.sur if not given.

TYPE: Optional[bool] DEFAULT: None

rng

Generator for the posterior draws. Defaults to a fresh numpy.random.default_rng() if not given.

TYPE: Optional[Generator] DEFAULT: None

RETURNS DESCRIPTION
SamplingResult

Dataclass containing posterior draws.

sample_posterior_state abstractmethod

sample_posterior_state(Y: ndarray, Z: ndarray, current_state: PosteriorState, rng: Optional[Generator] = None) -> PosteriorState

Return the next posterior state given the current one.

This is the sole posterior-update extension point: called each iteration by Forecasting._conditional_forecast, which threads a :class:PosteriorState through its Gibbs chain (seeded from a copy of BVAR.posterior_state_point) to re-sample parameters after augmenting the data with constrained forecasts, so model-owned extras persist across iterations. The method uses self.beta_0, self.V_A_inv, and self.pars (S_0, nu_0) that :meth:sample stored.

PARAMETER DESCRIPTION
Y

Dependent-variable matrix (with dummies already stacked if applicable).

TYPE: ndarray

Z

Regressor matrix (with dummies already stacked if applicable).

TYPE: ndarray

current_state

The previous draw's state. Direct samplers (e.g. :class:~bvar.models.conjugate.NaturalConjugate) sample independently and ignore this state. MCMC samplers (e.g. :class:~bvar.models.independent_niw.IndependentNIW) use current_state.sigma as the starting point for the next Gibbs sweep; the Independent-NIW Gibbs kernel does not need current_state.beta either — β is freshly sampled conditional on Σ within each sweep.

TYPE: PosteriorState

rng

Generator for the draw. Defaults to a fresh numpy.random.default_rng() if not given.

TYPE: Optional[Generator] DEFAULT: None

RETURNS DESCRIPTION
PosteriorState

The next draw's state. extras is None unless the model carries auxiliary state beyond beta/sigma, in which case the override should update and forward its own payload.

sample_innovations

sample_innovations(state: PosteriorState, H: int, rng: Optional[Generator] = None, point_only: bool = False) -> ndarray

Draw reduced-form forecast innovations for a complete posterior state.

Dispatched once per retained draw by Forecasting.recursive_forecast and Forecasting._unconditional_forecast, passing the draw's complete :class:PosteriorState (beta/sigma/extras) so models that carry auxiliary predictive state in extras (e.g. a sampled degrees of freedom parameter for a Student-t model) can shape the innovation distribution accordingly. The default implementation below only uses state.sigma and draws Gaussian reduced-form innovations ~ N(0, Sigma) -- the existing behaviour for every current model, which ignores extras. Models that need a different predictive distribution should override this method.

PARAMETER DESCRIPTION
state

Complete posterior draw state for this draw (or BVAR.posterior_state_point when point_only).

TYPE: PosteriorState

H

Forecast horizon (number of steps ahead).

TYPE: int

rng

Generator for the draw. Defaults to a fresh numpy.random.default_rng() if not given.

TYPE: Optional[Generator] DEFAULT: None

point_only

If True, return an all-zero array (point-estimate forecast, no random innovations). Default False.

TYPE: bool DEFAULT: False

RETURNS DESCRIPTION
ndarray

Reduced-form innovations, one row per forecast step.

RAISES DESCRIPTION
NotImplementedError

If supports_gaussian_predictive is False: the default Gaussian implementation does not apply, and the subclass must override this method.

sample_conditional_forecast

sample_conditional_forecast(state: PosteriorState, C: ndarray, f: ndarray, Sigma_f: ndarray, shape_f: ndarray, last_p_obs: ndarray, p: int, n: int, h: int, H: int, point_only: bool, constraint_sampler: Optional[Callable] = None, method: str = 'andersson_et_al', rng: Optional[Generator] = None) -> ndarray

Draw a constrained forecast for a complete posterior state.

Dispatched once per Gibbs iteration by Forecasting._conditional_forecast, passing the iteration's complete :class:PosteriorState (beta/sigma/extras) so models that carry auxiliary predictive state in extras can shape the constrained-forecast distribution accordingly. The default implementation below only uses state.beta/ state.sigma and routes to the existing :func:~bvar.forecast.conditional.draw_constrained_forecasts algorithm -- the existing behaviour for every current model, which ignores extras. Models that need a different predictive distribution should override this method.

PARAMETER DESCRIPTION
state

Complete posterior draw state for this Gibbs iteration.

TYPE: PosteriorState

C

Constraint-selection matrix, as returned by :func:~bvar.forecast.conditional.get_constraint, with shape (nb_constraints, H*n).

TYPE: ndarray

f

Constraint locations with shape (nb_constraints,).

TYPE: ndarray

Sigma_f

Constraint scale matrix with shape (nb_constraints, nb_constraints).

TYPE: ndarray

shape_f

Constraint shape parameters with shape (nb_constraints,).

TYPE: ndarray

last_p_obs

Last p observations before the forecast period, with shape (p, n).

TYPE: ndarray

p

Number of lags.

TYPE: int

n

Number of variables.

TYPE: int

h

Number of COVID dummies.

TYPE: int

H

Forecast horizon.

TYPE: int

point_only

If True, return only the conditional mean (no sampling).

TYPE: bool

constraint_sampler

Custom function to sample from the constraint distribution.

TYPE: Optional[Callable] DEFAULT: None

method

Algorithm: "andersson_et_al", "antolin_diaz_et_al", or "labonne_renzetti". Default "andersson_et_al".

TYPE: str DEFAULT: 'andersson_et_al'

rng

Generator for the draw. Defaults to a fresh numpy.random.default_rng() if not given.

TYPE: Optional[Generator] DEFAULT: None

RETURNS DESCRIPTION
ndarray

Forecast values (flattened), with shape (H*n,).

RAISES DESCRIPTION
NotImplementedError

If supports_gaussian_predictive is False: the default Gaussian implementation does not apply, and the subclass must override this method.

predictive_logpdf

predictive_logpdf(state: PosteriorState, observation: ndarray, mean: ndarray, covariance: ndarray) -> float

Evaluate the log predictive density of an out-of-sample observation.

Dispatched by GridSearch.marginal_likelihood_H for each rolling-window out-of-sample point, passing the fitted model's posterior_state_point so models that carry auxiliary predictive state in extras can shape the predictive distribution accordingly. The default implementation below only uses mean and covariance and evaluates the Gaussian scipy.stats.multivariate_normal.logpdf -- the existing behaviour for every current model, which ignores state.extras. Models that need a different predictive distribution should override this method.

PARAMETER DESCRIPTION
state

Complete posterior state (typically BVAR.posterior_state_point) accompanying mean/covariance.

TYPE: PosteriorState

observation

The realised out-of-sample observation with shape (n_targets,).

TYPE: ndarray

mean

Predictive mean at the forecast horizon with shape (n_targets,).

TYPE: ndarray

covariance

Predictive covariance at the forecast horizon with shape (n_targets, n_targets).

TYPE: ndarray

RETURNS DESCRIPTION
float

Log predictive density of observation.

RAISES DESCRIPTION
NotImplementedError

If supports_gaussian_predictive is False: the default Gaussian implementation does not apply, and the subclass must override this method.


bvar.models.SamplingResult dataclass

SamplingResult(beta_draws: ndarray, sigma_draws: ndarray, beta_point: ndarray, sigma_point: ndarray, extras_point: Optional[Any] = None, extras_draws: Optional[list] = None)

Container for the output of a model's sample() method.

ATTRIBUTE DESCRIPTION
beta_draws

Posterior draws of VAR coefficients (vectorised), with shape (N_draws, nk).

TYPE: ndarray

sigma_draws

Posterior draws of the covariance matrix (flattened), with shape (N_draws, n**2).

TYPE: ndarray

beta_point

Posterior point estimate of VAR coefficients, with shape (nk,).

TYPE: ndarray

sigma_point

Posterior point estimate of the covariance matrix, with shape (n**2,). For the conjugate model this is the posterior mean.

TYPE: ndarray

extras_point

Model-owned auxiliary state accompanying the point estimate, or None for models that carry no state beyond beta/sigma (the default for all current models).

TYPE: Optional[Any]

extras_draws

Model-owned auxiliary state for each retained draw, one entry per row of beta_draws/sigma_draws, or None for models that carry no per-draw state beyond beta/sigma (the default for all current models). Validated at construction (see :meth:__post_init__) to have exactly one entry per draw.

TYPE: Optional[list]

state_point property

state_point: PosteriorState

PosteriorState view of the posterior point estimates.

Built on demand rather than stored, so models that do not use extras_point incur no extra allocation.

__post_init__

__post_init__() -> None

Validate draw counts are consistent across beta/sigma/extras.

Catching a misalignment here -- rather than later, when forecasting indexes a row/entry by draw number -- turns a confusing IndexError/broadcasting error deep in the forecast loop into an immediate, clear ValueError.