Library / SDK
cdt15/lingam avatar
cdt15/lingam

LiNGAM: Causal Discovery That Assumes Your Noise Is Not Gaussian

Python package for causal discovery based on LiNGAM.

507 stars73 forksPythonMIT

At a glance

What is it?
The lingam package estimates linear non-Gaussian acyclic models in Python, and it ships several algorithm families under one API. The core judgement: it is a specialist instrument for linear structural equation models, not a general purpose causal workbench.
Who is it for?
Adopt lingam if your variables are continuous, your assumed structural equations are linear, and you have a reason to believe the disturbances are non-Gaussian; the package covers Basic, Direct, RESIT, VAR, VARMA, ParceLiNGAM, RCD, LiNA, GroupDirectLiNGAM and multi-group and longitudinal variants under one import.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 8 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What lingam solves, and for whom

Observational data alone does not tell you which variable causes which. LiNGAM attacks that problem from a specific angle: if the data generating process is linear and the disturbance terms are non-Gaussian, the causal ordering becomes identifiable from observational data without interventions. That is the whole premise, and the README states it plainly: the method is based on using the non-Gaussianity of the data. The audience is therefore narrow in a useful way. It is for researchers and engineers who already believe a linear structural equation model or linear Bayesian network is a defensible description of their system, and who need the direction of the arrows rather than just the strength of an association. Typical fits are gene expression panels, sensor arrays, financial factor models, and any setting where you can argue the error terms are not normal. If your data is Gaussian, the identifiability argument collapses and the method has nothing to work with. That is not a bug in the implementation; it is the mathematical boundary of the model class.

The mechanism: non-Gaussianity as the tie-breaker

Two variables that are jointly Gaussian cannot be oriented from observation alone, because the joint density is symmetric under swapping which one is the cause. LiNGAM escapes that symmetry by requiring the disturbances to be non-Gaussian. DirectLiNGAM, the default entry point in the README example, works by repeatedly finding the variable that is most independent of the residuals of the others, removing it, and appending it to the causal order. The package exposes the result through two attributes: causal_order_, which is the estimated ordering of the variables, and adjacency_matrix_, which encodes the estimated direct effects. The README example is short: construct lingam.DirectLiNGAM(), call fit(X), then read model.causal_order_ and model.adjacency_matrix_. Note what the API does not give you by default: a confidence interval, a p-value, or a bootstrap distribution. Those come from the separate bootstrap machinery in the package, not from the plain fit call. The repository also carries algorithm families beyond the basic linear acyclic case, including RESIT for continuous additive noise models, VAR-LiNGAM and VARMA-LiNGAM for time series, ParceLiNGAM, RCD and LiNA for latent confounders, and GroupDirectLiNGAM for groups of variables. Each has its own reference paper listed in the README, which is a fair signal that these are research implementations rather than a homogenised product surface.

Install and first fit

Installation is a single command: pip install lingam. The README lists the runtime requirements as numpy, scipy, scikit-learn, graphviz, statsmodels, networkx, pandas, itertools, semopy and autograd. Two of those deserve attention before you build a container image. graphviz is listed as a requirement, which usually means a system level binary in addition to the Python wrapper, so a slim base image will need the Graphviz package installed at the OS level before pip install lingam succeeds in producing plots. autograd pulls in automatic differentiation, which is a heavier dependency than a pure numpy estimator would need; if you are embedding this in a constrained environment, check what autograd drags along. The minimal working script, adapted from the README, is: import lingam, then model = lingam.DirectLiNGAM(), then model.fit(X), then print(model.causal_order_) and print(model.adjacency_matrix_). X here is your observation matrix. The README does not spell out the expected orientation of X in the snippet, so confirm from the API reference whether rows are samples or variables before you trust the output shape. The package also ships Jupyter notebooks under lingam/examples in the repository, which is the fastest way to see a full run including any preprocessing the authors apply.

Where it breaks: linearity, Gaussianity, and scale

The first failure mode is the one the method is named after. Feed DirectLiNGAM data whose disturbances are close to Gaussian and the ordering estimate becomes unstable; the algorithm still returns a causal_order_, but that ordering is not carrying the identification guarantee the theory promises. There is no built-in check in the fit call that refuses to run on Gaussian data. You have to test the residuals yourself. The second failure mode is linearity. RESIT is offered for continuous additive noise models, but the headline algorithms assume linear structural equations. A system with a threshold effect, a saturation, or a multiplicative interaction will be misrepresented, and the adjacency_matrix_ will report a linear approximation of something that is not linear. Third, the method is not built for high dimensional problems in the p greater than n regime without additional structure; the pairwise independence testing that drives the ordering degrades as the variable count grows relative to the sample count. Fourth, and this is a documentation gap rather than an algorithmic one, the README does not discuss how to choose among DirectLiNGAM, RCD, LiNA and ParceLiNGAM when latent confounders are suspected. The reference list tells you which paper each implements, but the selection guidance is left to you. If you have unmeasured common causes and you pick a variant that assumes none, the output will be confidently wrong.

The alternative worth comparing: causal-learn

The natural comparison is causal-learn, the Python package that grew out of the Tetrad project and implements constraint based discovery such as PC and FCI alongside score based methods like GES. The difference in approach is fundamental rather than cosmetic. Constraint based methods test conditional independences in the data and return a partially oriented graph, often a CPDAG or PAG, which is an honest representation of what observational data can and cannot identify. LiNGAM instead commits to a functional form, linear with non-Gaussian noise, and in exchange returns a fully oriented causal order. So the trade is this: causal-learn gives you weaker output with fewer assumptions and no distributional requirement, while lingam gives you a total order that is only as good as the linearity and non-Gaussianity assumptions behind it. If you cannot defend those two assumptions, a PAG from FCI is more useful than a wrong ordering from DirectLiNGAM. If you can defend them, lingam gives you something constraint based methods cannot: a definite direction for every edge, including edges that conditional independence tests would leave undirected. Note also that lingam's latent confounder variants, RCD and ParceLiNGAM, are trying to recover some of the ground that constraint based methods occupy by default, which is a sign that the pure acyclic no-confounder case is the easy case.

Maintenance, releases and what the MIT licence means here

The repository is active, not archived, with a last push in September 2026 and releases v1.13.0, v1.12.2 and v1.12.1 spread across 2025 and 2026. The cadence looks like a maintained research package rather than a fast moving library: roughly two to three tagged releases a year in the visible window. That matters for upgrade cost. You are unlikely to face weekly breaking changes, but you should also not expect a deprecation policy with long overlap windows, since the release notes are the only place a change would be announced. The dependency list is the real maintenance burden. autograd, semopy, statsmodels and graphviz all move independently, and a pinned environment will need periodic attention even when lingam itself has not changed. On licensing: the project is MIT, which is permissive and permits commercial embedding, modification and redistribution provided the copyright notice and licence text are retained. That is the general shape of MIT, not legal advice, and you should have counsel review anything you ship. Separately, the README makes a citation request that is not a licence condition but is clearly the authors' expectation: cite the JMLR package paper, and cite the specific algorithm paper for whichever method you call. If you use ICA based LiNGAM, DirectLiNGAM, RESIT, GroupDirectLiNGAM, VAR-LiNGAM, VARMA-LiNGAM, the multi-group or longitudinal variants, or BottomUpParceLiNGAM, RCD and LiNA, the README names a different reference for each.

Verifying a lingam result before you act on it

Because fit returns a point estimate with no uncertainty attached, the verification step is not optional. The package includes bootstrap functionality for this purpose, and the repository examples show it in use; the plain DirectLiNGAM fit in the README does not. A practical check is to refit on resampled data and look at how often each pairwise ordering in causal_order_ survives. Orderings that flip across resamples should not be reported as findings. The second check is distributional: pull the residuals from the fitted linear model and look at them. If they pass a normality test, the identification argument does not apply to your data and you should say so rather than reporting the ordering. The third check is against prior knowledge. If you have even a partial ordering you trust from domain expertise or from an experiment, compare it to causal_order_. A method that disagrees with a known ordering on the pairs you can check is not one to trust on the pairs you cannot. None of these checks appear as automated warnings in the fit call, so they have to be built into whatever pipeline consumes the output.

Editorial conclusion

Adopt lingam if your variables are continuous, your assumed structural equations are linear, and you have a reason to believe the disturbances are non-Gaussian; the package covers Basic, Direct, RESIT, VAR, VARMA, ParceLiNGAM, RCD, LiNA, GroupDirectLiNGAM and multi-group and longitudinal variants under one import. Do not adopt it if your relationships are known to be non-linear in the mean or if you need a method that works from conditional independence tests over arbitrary distributions; for that, look at causal-learn or DoWhy instead. Before committing, verify three things on your own data: that DirectLiNGAM returns a causal_order_ consistent with whatever domain ordering you already trust, that the residuals from the fitted linear model are visibly non-Gaussian, and that the adjacency_matrix_ is stable when you refit on a bootstrap resample. The MIT licence lets you embed it, but the README asks you to cite the JMLR package paper plus the paper for whichever algorithm you actually call.

Official sources

  1. cdt15/lingam on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes