ConditionalSpectralCausalityResult#

class cultivars.spectral.causality.ConditionalSpectralCausalityResult(*, cause, effect_names, frequencies, measure, consistency)[source]

Bases: _SummaryMixin

Geweke’s conditional measure from one cause to every other variable.

For a cause \(x\), an effect \(y\), and the remaining variables \(z\), the conditional measure at frequency \(\omega\) is

\[f_{x \to y \mid z}(\omega) = \ln \frac{\Sigma^{r}_{yy}} {\bigl|Q_{yy}(\omega)\bigr|^2 \, \tilde\Sigma_{yy}} \;\ge\; 0,\]

where \(\Sigma^{r}_{yy}\) is \(y\)’s innovation variance in the restricted system fitted without \(x\), and the denominator is the part of that innovation power the full system attributes to innovations other than \(x\)’s once the full model’s shocks are mapped through the restricted lag polynomial \(Q(\omega)\). What remains is the power in \(y\)’s restricted innovation that traces back to \(x\)’s shocks: \(x\)’s contribution to \(y\) given every other variable’s history, which the pairwise unconditional measure cannot separate from common driving.

Variables:
  • cause – The variable whose history is being credited.

  • effect_names – The remaining variables, in the restricted model’s order.

  • frequencies – The (n,) grid on [0, pi].

  • measure – The (n, k - 1) measure per effect.

  • consistency – The largest relative gap between the transformed full model’s implied innovation spectrum and the restricted model’s innovation variance – exactly zero in population, and a diagnostic for how compatible the two separately fitted models are. Large values mean the restricted model is badly specified relative to the full one, and the curves should be read with suspicion.

Note

The measure is one cause against every effect, not a matrix: a different cause needs a different restricted model, so it is a different ConditionalSpectralCausality. The consistency number has no threshold the literature supplies; it is the relative size of the mismatch between two models that would agree exactly if both were true, and values around a tenth are ordinary for a finite-order restricted VAR standing in for a VARMA process. A jump when the restricted lag order is reduced is the signal that the restricted model is too short.

See also

References

Geweke, J. (1984). Measures of conditional linear dependence and feedback between time series. Journal of the American Statistical Association, 79(388), 907-915.

Ding, M., Chen, Y., & Bressler, S. L. (2006). Granger causality: Basic theory and application to neuroscience. In Handbook of Time Series Analysis (pp. 437-460). Wiley.

Example

A third variable drives the first two; unconditionally the second looks causal for the first, and conditioning on the driver removes it:

>>> import numpy as np
>>> from cultivars.multivariate.reduced_form.vector_autoregression import VAR
>>> rng = np.random.default_rng(0)
>>> z = np.zeros((800, 3))
>>> for t in range(1, 800):
...     z[t, 2] = 0.6 * z[t - 1, 2] + rng.standard_normal()
...     z[t, 0] = 0.3 * z[t - 1, 0] + 0.8 * z[t - 1, 2] + rng.standard_normal()
...     z[t, 1] = 0.3 * z[t - 1, 1] + 0.8 * z[t - 1, 2] + rng.standard_normal()
>>> full = VAR(z, order=1).fit()
>>> pairwise = SpectralCausality(full, n_frequencies=64).compute().integrated()
>>> without = VAR(z[:, [0, 2]], order=3, names=("y1", "y3")).fit()
>>> given = ConditionalSpectralCausality(full, without, n_frequencies=64).compute()
>>> given.cause, given.effect_names, given.measure.shape
('y2', ('y1', 'y3'), (64, 2))
>>> bool(pairwise[0, 1] > 0.01), bool(given.integrated()[0] < 0.001)
(True, True)
>>> bool(given.consistency < 0.2)
True

Private methods#

_index(name)

The column index of an effect label, after checking it exists.

_summary_table()

Build the structured summary: one row per effect, largest first.