NonGaussianSVAR.identify#

NonGaussianSVAR.identify()[source]#

Recover the impact matrix by restoring shock independence.

Whitens the residuals, warm-starts at the FOBI eigenvectors, refines them by joint diagonalization of the third- and fourth-order cumulant slices, orders the columns by descending absolute excess kurtosis, and signs each column so its largest entry is positive.

Return type:

SVARResult

Returns:

The complete structural result, shock columns in descending order of absolute excess kurtosis, with each shock’s skewness and excess kurtosis, the co-diagonalization residual and the Gaussianity verdict in its diagnostics.

Raises:

NumericalError – If the innovation covariance is not positive definite.

Example

Gaussian innovations carry no identifying information: the scheme still returns a rotation, and the verdict says the data could not have chosen it:

>>> import numpy as np
>>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR
>>> rng = np.random.default_rng(0)
>>> B = np.array([[1.0, 0.5], [0.3, 1.0]])
>>> y = np.zeros((602, 2))
>>> for t in range(1, 602):
...     y[t] = 0.4 * y[t - 1] + B @ rng.standard_normal(2)
>>> res = VAR(y, order=1).fit()
>>> svar = NonGaussianSVAR(res).identify()
>>> svar.is_complete, dict(svar.diagnostics)["Identification"]
(True, 'WEAK: 2 shocks statistically Gaussian')
>>> bool(np.allclose(svar.impact @ svar.impact.T, res.resid.T @ res.resid / 601))
True