NonGaussianSVAR#

class cultivars.multivariate.structural.non_gaussian.NonGaussianSVAR(result, *, shock_names=None)[source]

Bases: _IdentificationModel[SVARResult]

Identification from shock independence and non-Gaussianity, Comon (1994).

Whiten the innovations by the Cholesky factor of their second moment, \(w_t = L^{-1} u_t\), so that any impact matrix consistent with the covariance is \(B = L Q\) for an orthogonal \(Q\). If the structural shocks \(\varepsilon_t = Q' w_t\) are mutually independent and at most one is Gaussian, \(Q\) is unique up to column order and sign: independence makes every third- and fourth-order cumulant slice of the shocks diagonal, and only the Gaussian direction leaves those slices invariant under rotation. The estimator finds the \(Q\) that jointly diagonalizes the empirical cumulant slices of \(w_t\), warm-started at the eigenvectors of the kurtosis-weighted covariance (the FOBI solution).

Shocks are unit variance, ordered by descending absolute excess kurtosis – the most non-Gaussian first – and labelled as the statistical objects they are. The summary reports each shock’s skewness and excess kurtosis: they are the scheme’s entire empirical content, and a shock with both inside sampling noise is one the data could not have separated, which the identification flag says plainly.

Note

The identifying assumptions are statistical and stated as such. Independence is strictly stronger than the uncorrelatedness every scheme imposes – it rules out, for instance, common volatility across shocks, which makes the shocks dependent through their second moments even when uncorrelated – and the at-most-one-Gaussian condition is what the Identification diagnostic checks. As with heteroskedasticity, the data identify and the user labels: the default names are shock1 ... shockk on purpose, and an economic name for a column is a claim argued from outside the model.

Variables:
  • _source – The closed reduced-form result being identified.

  • _labels – The shock labels, in descending-kurtosis column order.

See also

  • SVARResult – the complete result returned.

  • HeteroskedasticSVAR – identification from second-moment shifts across declared regimes, on the same joint-diagonalization surface.

References

Comon, P. (1994). Independent component analysis, a new concept? Signal Processing, 36(3), 287-314.

Cardoso, J.-F., & Souloumiac, A. (1993). Blind beamforming for non-Gaussian signals. IEE Proceedings F, 140(6), 362-370.

Lanne, M., Meitz, M., & Saikkonen, P. (2017). Identification and estimation of non-Gaussian structural vector autoregressions. Journal of Econometrics, 196(2), 288-304.

Gouriéroux, C., Monfort, A., & Renne, J.-P. (2017). Statistical inference for independent component analysis: Application to structural VAR models. Journal of Econometrics, 196(1), 111-126.

Example

A heavy-tailed shock and a flat-tailed one mixed through a non- triangular impact matrix. Independence recovers both columns up to scale with no economic restriction, the heavy-tailed shock comes first, and the recovered shock series track the truth:

>>> 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]])
>>> heavy = rng.laplace(size=602) / np.sqrt(2)
>>> flat = rng.uniform(-np.sqrt(3), np.sqrt(3), size=602)
>>> eps = np.column_stack([heavy, flat])
>>> y = np.zeros((602, 2))
>>> for t in range(1, 602):
...     y[t] = 0.4 * y[t - 1] + B @ eps[t]
>>> res = VAR(y, order=1, names=("a", "b")).fit()
>>> svar = NonGaussianSVAR(res, shock_names=("heavy", "flat")).identify()
>>> svar.is_complete, svar.shock_names, dict(svar.diagnostics)["Identification"]
(True, ('heavy', 'flat'), 'at most one Gaussian shock')
>>> dict(svar.diagnostics)["Excess kurtosis"]
'3.249, -1.196'
>>> unit = lambda v: v / np.linalg.norm(v)
>>> bool(np.abs(unit(svar.impact[:, 0]) - unit(B[:, 0])).max() < 0.07)
True
>>> recovered = svar.structural_shocks()
>>> bool(np.corrcoef(recovered[:, 1], flat[1:])[0, 1] > 0.99)
True

Private attributes#