API reference

andrey.varma_lingam#

andrey.varma_lingam(data, *, order=(1, 1), criterion=None, prune=False, structural_ma=False, max_iter=100)[source]#

Learn a temporal causal structure from one multivariate time series with VARMA-LiNGAM.

VARMA-LiNGAM [1] fits a vector autoregressive moving-average model, then applies LiNGAM to the residuals to fix a causal order over the instantaneous (contemporaneous) effects [2]. Use it when a single multivariate series carries both same-step and lagged causal influence.

Parameters:
  • data (ArrayLike) – A multivariate time series, one row per time step. Coerced to float64. A DataFrame’s column names become the structure’s labels.

  • order (tuple[int, int]) – The (p, q) autoregressive and moving-average lag counts, each at least 0 and not both 0.

  • criterion (str | None) – Order-selection criterion. When set, (p, q) is chosen by that information criterion over 0 <= p <= order[0] and 0 <= q <= order[1], excluding (0, 0); None uses order directly.

  • prune (bool) – Re-estimate the weights on the causal order: adaptive Lasso sets small weights to zero and least squares refits the rest. With False every lagged weight is nonzero, so every lag graph links every pair of variables, self-loops included.

  • structural_ma (bool) – How the moving-average weights are expressed: True maps them onto the independent noise terms, (I - B0) Theta_j (I - B0)^-1 [1]; False uses (I - B0) Theta_j. B0 is the lag-0 weight matrix and Theta_j the fitted moving-average coefficients. Ignored when prune=True.

  • max_iter (int) – Most iterations of the likelihood fit, at least 1. With criterion set, every fit in the grid gets this limit.

Returns:

Wraps a temporal TemporalStructure. structure.lag_weights[k][i, j] is the autoregressive weight of edge i -> j at lag k, lag 0 being instantaneous; structure.lag_weights_ma[k] holds the moving-average weights at lag k + 1, in the same orientation. The lag graphs follow the autoregressive weights. ordering is the instantaneous causal order, and metadata["algorithm"] is "varmalingam".

Return type:

StructureOutput

Raises:
  • TypeError – If order is not a pair of ints, or max_iter is not an int.

  • ValueError – If criterion is not one of "aic", "bic", "hqic", or None, if order holds a negative count or is (0, 0), if max_iter is below 1, or if data has fewer than 2 columns.

Notes

DirectLiNGAM orders the innovations of the fitted model. Each pairwise regression in its ordering takes the least-squares slope, so every residual it scores is uncorrelated with its regressor in the sample.

With prune=True each variable is regressed on its causal predecessors at the same step, the lagged values of every variable, and the lagged independent noise terms. Adaptive Lasso selects the regressors, and an ordinary least-squares fit with an intercept on the selected ones gives their weights, so the kept weights are not shrunk toward zero. The noise terms come from a lag-0 matrix refit the same way. The regressions start at time step max(p, q): the first steps serve only as lagged values. No lagged value wraps around from the end of the series, so no step is regressed on a later one.

Column order. The fit runs on the columns sorted by a rank computed from each column’s own data, as for hc(), so reordering the columns relabels the result and changes nothing else, unless two columns are identical.

Limitations. Measured on simulated linear series with non-Gaussian noise, one autoregressive and one moving-average lag, from 3 to 20 variables with 100 to 1,000 time steps, with order=(1, 1) and prune=True. Its median errors (missing and extra cross-links) stayed below the empty graph’s from 300 time steps at every size; at 100 time steps they exceeded it from 10 variables on. The fit takes minutes at 20 variables and 1,000 time steps. It assumes linear effects and non-Gaussian noise. The likelihood fit can stop before it converges, and gives no warning; a larger max_iter does not prevent this. The result then depends on the versions of the numerical libraries, so the same series can give a different graph in another environment. With criterion set, it fits one model for every (p, q) in the grid.

References

Examples

>>> import numpy as np
>>> from andrey import varma_lingam
>>> rng = np.random.default_rng(0)
>>> x = rng.uniform(-1, 1, 300)
>>> y = np.r_[0.0, 0.8 * x[:-1]] + rng.uniform(-1, 1, 300)
>>> out = varma_lingam(np.column_stack([x, y]), order=(1, 1), prune=True)
>>> out.structure.lag(1).oriented_edges()
[(0, 1, 'directed')]