BVARResult.forecast_paths#

BVARResult.forecast_paths(steps=8, *, seed=None)[source]#

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

Draw s simulates its own future from the end of the sample,

\[y^{(s)}_{T+h} = d_{T+h}^\top \beta^{(s)}_{\text{det}} + \sum_{l=1}^{p} A_l^{(s)}\, y^{(s)}_{T+h-l} + P^{(s)} \varepsilon^{(s)}_h, \qquad \varepsilon^{(s)}_h \sim \mathcal{N}(0, I_k),\]

for h = 1 .. steps, where \(y^{(s)}_{T+h-l}\) is the observed value when T + h - l <= T and the path’s own earlier simulated value otherwise, \(d_{T+h}\) is the deterministic row (1 and, for "ct", the continued time index T + h), and \(P^{(s)}\) is the lower Cholesky factor of \(\Sigma^{(s)}\). Across draws the paths are samples from the joint posterior predictive

\[p(y_{T+1:T+H} \mid Y) = \int p(y_{T+1:T+H} \mid B, \Sigma, Y)\, p(B, \Sigma \mid Y) \, dB\, d\Sigma,\]

parameter uncertainty and shock uncertainty integrated together.

The paths are returned unsummarized because the summary loses what most downstream uses need. A density score needs the sample, not three quantiles; a fan chart takes its own quantiles at its own levels; a model average mixes paths across models; and any path-dependent quantity – cumulative growth over the horizon, the probability that a series stays below a threshold for every lead – is a function of whole paths, which the per-lead quantiles of forecast() cannot recover. Each path is one draw’s future, so the joint distribution across leads is preserved.

Parameters:
  • steps (int) – Horizons ahead H; the paths cover T + 1 .. T + H.

  • seed (int | Generator | None) – Seed or generator for the predictive shocks. An integer gives a fresh generator and a reproducible array; a numpy.random.Generator is used in place and advanced, so two calls with the same generator object give different paths.

Return type:

NDArray[double]

Returns:

An array of shape (n_kept, steps, k); entry [s, h, i] is draw s’s simulated value of variable i at lead h + 1.

Raises:

SpecificationError – If steps is not positive.

Example

>>> 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)
>>> paths = res.forecast_paths(4, seed=1)
>>> paths.shape
(200, 4, 2)
>>> np.allclose(paths, res.forecast_paths(4, seed=1))
True

A path-dependent probability – that cumulative growth over the four leads is negative – is a mean over paths:

>>> prob = (paths[:, :, 0].sum(axis=1) < 0).mean()
>>> bool(0.0 <= prob <= 1.0)
True

See also

  • forecast() – the (16th, mean, 84th) summary of these paths.

  • fan_chart() – quantile fans from the paths.

  • DensityScore – scores the predictive sample against realized values.

  • bayesian_model_average() – mixes paths across models by posterior model probability.