andrey.direct_lingam#
- andrey.direct_lingam(data, *, random_state=None, measure='pwling', knowledge=None)[source]#
Learn a fully oriented DAG with DirectLiNGAM (linear, non-Gaussian noise).
DirectLiNGAM uses non-Gaussianity - noise that is not Gaussian - to determine a complete causal order, then estimates linear edge weights. It returns a single fully oriented DAG (directed acyclic graph), with edge weights and a total ordering. PC and GES instead return an equivalence class.
- Parameters:
data (
ArrayLike) – Observed data, one row per sample. Coerced tofloat64. A DataFrame’s column names become the structure’slabels.random_state (
int|None) – Ignored. DirectLiNGAM withmeasure="pwling"is deterministic; the argument exists so thatdirect_lingamacceptsrandom_stateasica_lingamdoes.measure (
str) – How the order search picks the most exogenous remaining variable at each step. Only"pwling", the pairwise likelihood-ratio measure [2], is supported.knowledge (
Knowledge|None) – Background knowledge, aKnowledge: required and forbidden edges, the pairs allowed to be adjacent, and temporal tiers, all honored. The causal order puts the cause of each required edge, and each earlier tier, first; the regression on that order drops the forbidden parents and does not penalize the required ones. A variable with a required parent takes least-squares weights on the parents it keeps; the others keep the adaptive Lasso’s. Every required edge is in the DAG, even where its least-squares weight is0.
- Returns:
Wraps a
dagGraphStructure;metadata["algorithm"]is"DirectLiNGAM".orderingis the causal order as a tuple of column indices, causes first.weighted_adjacency[i, j]is the coefficient of edgei -> j, estimated by adaptive Lasso, or by least squares for a copy (see Notes) and for a variable with a required parent; the DAG has an edge where the coefficient is nonzero and at every required edge.- Return type:
- Raises:
NotImplementedError – If
measureis not"pwling".ValueError – If
datais not a usable 2-D matrix: not numeric, holdingNaNorinf, or with a constant column, named in the message. Also if it has fewer thann_variables + 1rows, the fewest with which the pruning step can estimate the edge weights. Also ifknowledgenames a columndatalacks or contradicts itself, asKnowledgelists.
Notes
When to use it. DirectLiNGAM suits continuous data with linear effects, independent non-Gaussian noise, and no unmeasured common causes [1]. These assumptions allow the causal order to be identified. The result includes a DAG with every edge oriented, the edge weights, and the order.
When not to. With Gaussian noise, the order cannot be identified, so the returned order is unreliable. Use
pc()orges(), which return the equivalence class. When unmeasured common causes are plausible, usefci().Cost. Each step compares the remaining variables in pairs, so runtime grows quickly with the number of variables. With the
torchextra and a CUDA GPU, entropy computations move to the GPU once they are large enough.Ties. Two candidates that are interchangeable in the sample, such as two binary columns with the same number of ones, have equal scores up to rounding, which differs between CPUs. Each step treats candidates as tied when the square roots of their negated scores lie within
1e-10of the best one, and picks among them by a rank computed from each column’s own data, ashc()does. The column-order guide says what the rank keeps under a new column order and on another machine.Copies. Two columns are copies when one leaves at most
1e-12of the other’s variance unexplained, as for a column and a rescaled or rank-reversed copy of it. Each step scores one column per group of copies, the one that ranks first by the same rank, and when it is picked the other copies follow it directly in the order. Each of them gets a single edge from it, weighted by the scale between the two, and no edges to later columns, which take their edges from the column it copies.Limitations. Measured on simulated data from scale-free graphs with linear effects and uniform noise, with ten rows per variable. From 20 to 200 variables its median errors (SHD) stayed below the empty graph’s, 13 against 199 at 200, and the median fit took 0.19 s at 20 variables and 545 s at 200, on 16 CPU cores. In a separate run on shared nodes, a CPU fit at 300 variables did not finish its warm-up and timed fit within 3,600 s; with an NVIDIA A100 GPU, a fit took 528 s at 300 variables and 1,410 s at 400.
References
Examples
>>> import numpy as np >>> from andrey import direct_lingam >>> rng = np.random.default_rng(0) >>> x = rng.uniform(-1, 1, 500) >>> y = 0.8 * x + rng.uniform(-1, 1, 500) >>> out = direct_lingam(np.column_stack([x, y])) >>> out.structure.kind, out.ordering ('dag', (0, 1))