TVPVARResult#

class cultivars.multivariate.nonlinear.time_varying.TVPVARResult(*, endog, names, order, trend, training, nobs, beta_mean, beta_low, beta_high, beta_draws, state_cov, sigma_u, resid, fittedvalues, n_draws, n_burn, thin)[source]

Bases: _SummaryMixin, _ConvergenceMixin

A fitted time-varying-parameter VAR, homoskedastic innovations.

The posterior of

\[y_t = X_t' \beta_t + u_t, \qquad u_t \sim N(0, \Sigma), \qquad \beta_t = \beta_{t-1} + \eta_t, \qquad \eta_t \sim N(0, Q),\]

with \(X_t\) the Kronecker-stacked design and \(\beta_t\) the \(D = k\,w\) coefficients of all equations stacked equation-major, reached by Gibbs sampling: each coefficient path is one Durbin-Koopman simulation-smoother draw given \((Q, \Sigma)\), and the two covariances are conjugate inverse-Wishart draws given the path. Every coefficient is a path: the posterior over \(\beta_t\) is summarized by its mean and a 68% band, with the kept draws retained so downstream consumers – the structural wrapper, custom summaries – can propagate posterior uncertainty rather than plugging in a point.

Deliberately absent: llf, n_params, information criteria. A Gibbs posterior has none of them, and this result will not counterfeit the comparison surface of a likelihood fit.

Note

The first training rows calibrated the priors – the initial state from their OLS estimate, the drift covariance \(Q\) from k_drift times that estimate’s covariance – and were then discarded, so every path here is indexed on the nobs rows that follow. How much the coefficients are allowed to move is a prior choice, not a finding: under Primiceri’s default k_drift = 0.01 a slow deterministic drift of several tenths over two hundred observations is shrunk to a few hundredths, and the drift note in the summary compares the posterior mean’s movement with its band for that reason. The point summaries (sigma_u, state_cov, resid, fittedvalues) are at posterior means. The draws are a Markov chain; convergence() reads them.

Variables:
  • endog – The observed panel.

  • names – Variable labels, in column order.

  • order – Autoregressive order.

  • trend – Deterministic specification.

  • training – Rows consumed by the training prior and then discarded.

  • nobs – Estimation rows after the training split.

  • beta_mean – (nobs, D) posterior mean coefficient path, stacked equation-major.

  • beta_low – (nobs, D) posterior 16th percentile path.

  • beta_high – (nobs, D) posterior 84th percentile path.

  • beta_draws – (S, nobs, D) kept coefficient-path draws.

  • state_cov – (D, D) posterior mean drift covariance Q.

  • sigma_u – (k, k) posterior mean innovation covariance.

  • resid – Residuals at the posterior mean path.

  • fittedvalues – One-step means at the posterior mean path.

  • n_draws – Total sampler iterations.

  • n_burn – Burn-in discarded.

  • thin – Post-burn thinning.

See also

  • TVPVAR – the model that produces this record.

  • TVPVARSVResult – the same paths with drifting volatility.

  • TVPSVAR – the recursive structural reading of either.

  • BVARResult – the constant-coefficient posterior these paths relax.

References

Primiceri, G. E. (2005). Time varying structural vector autoregressions and monetary policy. Review of Economic Studies, 72(3), 821-852.

Cogley, T., & Sargent, T. J. (2005). Drifts and volatilities: Monetary policies and outcomes in the post WWII US. Review of Economic Dynamics, 8(2), 262-302.

Example

A bivariate system whose first own-lag coefficient drifts linearly from 0.2 to 0.8; with a loose drift prior the posterior mean path climbs by several tenths, its band brackets the path throughout, and the local companion root rises with it:

>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> y = np.zeros((240, 2))
>>> phi = np.linspace(0.2, 0.8, 240)
>>> for t in range(1, 240):
...     y[t, 0] = phi[t] * y[t - 1, 0] + rng.standard_normal()
...     y[t, 1] = 0.4 * y[t - 1, 1] + 0.3 * y[t - 1, 0] + rng.standard_normal()
>>> res = TVPVAR(y, order=1, training=40).fit(
...     n_draws=60, n_burn=20, k_drift=0.3, seed=0
... )
>>> res.training, res.nobs, res.n_kept, res.beta_mean.shape, res.beta_draws.shape
(40, 199, 20, (199, 6), (20, 199, 6))
>>> path = res.coefficient_path("y1", "y1.L1")
>>> bool(path[-1, 1] - path[0, 1] > 0.25), bool(np.all(path[:, 0] < path[:, 2]))
(True, True)
>>> roots = res.stability_path()
>>> bool(roots[-1] > roots[0]), bool(roots.max() < 1.0)
(True, True)
>>> res.sigma_u.shape, res.state_cov.shape
((2, 2), (6, 6))

Private attributes#

_n_deterministic

Deterministic columns per equation.

_width

Regressors per equation, w = n_det + k p; the state has k w entries.

Private methods#

_drift_note()

One line on how much the coefficients actually moved.

_family()

Specification stem for display.

_regressor_labels()

Per-equation regressor labels, in design order.

_summary_table()

Build the structured summary.