cultivars.multivariate.reduced_form.vector_autoregression#
The reduced-form vector autoregression: the root of the multivariate surface.
A VAR(p) with deterministic terms,
is estimated by multivariate least squares, which is equation-by-equation OLS and, under Gaussian innovations, maximum likelihood at the same time. The estimate itself is three arrays – the coefficient stack, the innovation covariance, the residuals – and the point of the module is what those three arrays are then made to answer: forecasts, impulse responses, the forecast-error variance decomposition, the historical decomposition, Granger causality, stability, lag selection, residual diagnostics and coefficient inference. The VARX adds a distributed lag of weakly exogenous regressors to the design and inherits every one of those answers unchanged, because \(x\) is conditioned on rather than shocked and so never enters the moving-average representation; its forecast alone is new, and it is conditional on a supplied path for \(x\).
Two commitments shape the surface. First, the inference lives on the arrays,
not on the estimator. Everything past the fit is written once on two mixins
in _internals – propagation (companion form, stability, the
moving-average representation, impulse responses, decompositions, forecasts,
simulation) and inference (Granger and residual tests, coefficient
covariance and its standard errors) – and neither asks how the arrays were
produced. That is what lets a VARX, a panel VAR, a VECM and a VARMA present
the same surface by supplying a different regressor block, a different
restriction or a different solve. Second, the one structural object on a
reduced-form result is labelled as such. An orthogonalized impulse
response requires a Cholesky factor, the factor is lower-triangular, and
triangularity is a recursive identifying restriction on the order of
names: permute the variables and the answer changes, while the forecast,
the Granger tests and the reduced-form responses do not. The result reports
it because everyone wants it, says on every summary that it is a recursive
SVAR whose assumption has not been declared, and points at
structural, where the declaration goes.
Layout. VAR is a thin fit() over
_VectorAutoRegressionModel in _internals, which validates the sample
through validate_endog_matrix in _core, lays out
[deterministic | lags] with deterministic_columns and lag_matrix,
solves by _least_squares – or by _shrunk_moments when a prior from
priors is attached – and offers
lag_order_selection before any fit. VARX extends it with
_ExogenousVectorAutoRegressionModel, which appends the exogenous block
after the lags so that every offset the base computes stays correct
without an override. VARResult and VARXResult are
_VectorResult records carrying the summary, comparison, inference and
propagation mixins; the VARX result adds the distributed-lag accessors, the
conditional forecast and to_varx, the levels form that
closed_global consumes. The
Cholesky caveat the summaries print is _CHOLESKY_NOTE in _core.
References
Sims, C. A. (1980). Macroeconomics and reality. Econometrica, 48(1), 1-48.
Lütkepohl, H. (2005). New Introduction to Multiple Time Series Analysis. Springer. Chapters 2-4 and 10.
Hamilton, J. D. (1994). Time Series Analysis. Princeton University Press. Chapter 11.
Example
A bivariate VAR(1) whose innovations are contemporaneously correlated. The same data fitted in the two variable orders give the same forecasts and the same Granger verdicts, and orthogonalized impulse responses that differ by more than a relabelling: the ordering is the identification.
>>> import numpy as np
>>> rng = np.random.default_rng(0)
>>> A = np.array([[0.5, 0.2], [0.0, 0.4]])
>>> y = np.zeros((202, 2))
>>> for t in range(1, 202):
... u = rng.standard_normal(2)
... u[1] += 0.8 * u[0]
... y[t] = A @ y[t - 1] + u
>>> y = y[2:]
>>> ab = VAR(y, order=1, names=("a", "b")).fit()
>>> ba = VAR(y[:, ::-1], order=1, names=("b", "a")).fit()
>>> bool(np.allclose(ab.forecast(3), ba.forecast(3)[:, ::-1]))
True
>>> ab.granger_causality("b", "a").reject() == ba.granger_causality("b", "a").reject()
True
>>> swapped = ba.irf(2)[:, ::-1, ::-1]
>>> bool(np.allclose(ab.irf(2), swapped)), round(float(np.abs(ab.irf(2) - swapped).max()), 2)
(False, 0.84)
>>> plain_ab, plain_ba = ab.irf(2, orthogonalized=False), ba.irf(2, orthogonalized=False)
>>> bool(np.allclose(plain_ab, plain_ba[:, ::-1, ::-1]))
True
Classes#
Reduced-form vector autoregression, estimated by multivariate least squares. |
|
Vector autoregression with exogenous regressors, estimated by least squares. |
|
A fitted reduced-form vector autoregression. |
|
A fitted vector autoregression with exogenous regressors. |