Model or dataset
BiomedSciAI/causallib avatar
BiomedSciAI/causallib

causallib: modular causal inference on top of scikit-learn estimators

A Python package for modular causal inference analysis and model evaluations

837 stars111 forksPythonApache-2.0

At a glance

What is it?
causallib wraps ordinary scikit-learn models in causal estimators and adds an evaluation suite. It is strongest when you already have a clean treatment column, a defensible confounder set, and a reason to prefer potential outcomes over a single effect number.
Who is it for?
Adopt causallib if your team already writes scikit-learn pipelines, your treatment is a discrete column you can defend, and you want potential outcomes computed out-of-bag rather than a single effect number. Do not adopt it if you expect the library to select confounders or validate your DAG; the README states plainly that this requires domain expert knowledge and is not automated.
Can I use it commercially?
Yes. Apache-2.0 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 112 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

The problem causallib addresses: separating effect estimation from outcome prediction

Most Python machine learning tooling predicts an outcome. Causal questions ask what would have happened under a different treatment, and that requires two potential outcomes per unit, only one of which is observed. causallib is built around that split. The README describes a two-step approach: fit a model that predicts potential outcomes, then estimate the effect from those predictions. The authors note a practical consequence of this design. Because the effect step is separate, multi-treatment problems work even when a single scalar effect is not well-defined. The intended user is someone with observational data, a treatment column, and a set of covariates they believe are confounders. The package does not try to be a graphical model or a DAG library. It assumes the data you hand it already satisfies your inclusion criteria, and the README says filtering can be applied at fit time through a scikit-learn pipeline that chains preprocessing steps in front of the causal model.

Two estimator families and what each one can output

The README draws a line between weight models and direct outcome models. Weight models reweight the sample so treated and control groups are balanced, then take a weighted average of observed outcomes. Inverse probability of treatment weighting is the named example, exposed as IPW. Direct outcome models use covariates and treatment assignment together to predict the outcome, then predict under an assignment of all controls or all treated. The README calls these standardization models and states that, currently, they are the only ones able to produce individual effect estimates, otherwise known as CATE. That sentence is the most consequential line in the documentation for anyone choosing between the two families. If you need a per-unit effect, weighting alone will not give it to you. The split also means the inner learner matters. causallib accepts any model with a scikit-learn-like fit-predict API, and the README adds a caveat that some models might require a predict_proba implementation. That caveat is easy to miss and it determines whether IPW can be constructed at all with a given estimator.

Out-of-bag estimation and why the target population is your decision

The API follows fit and predict. You fit on one set of examples and estimate an effect on another, which the README describes as out-of-bag estimation and links to Wager and Athey's terminology about avoiding overfit. This is a design position, not a convenience. It means causallib will not silently report an in-sample effect and call it average treatment effect. The README is explicit that the population is left to the user: ATE comes from model.estimate_population_outcome(X, a), while ATT comes from stratifying on the treated with model.estimate_population_outcome(X.loc[a==1], a.loc[a==1]). That second call is worth reading twice, because it shows the mechanism. There is no target_population argument. You subset the data yourself and the estimator reports on whatever sample you passed. For anyone used to libraries that take a parameter for the estimand, this is a lower-level interface, and it puts the burden of getting the sample right on the caller.

Getting it running: install, import, and the README's working example

Installation is a single command, pip install causallib. The import name is causallib, matching the distribution name. The README's example loads a bundled dataset through causallib.datasets.load_nhefs, wraps a scikit-learn LogisticRegression in IPW, fits on the covariates and treatment, then calls estimate_population_outcome and estimate_effect. Note the argument order in fit: data.X first, then data.a. The treatment is passed separately from the outcome, and the outcome appears only at estimation time. That ordering is the API's way of enforcing the potential-outcome framing. If you want to see the package in use before installing anything, the README links a Binder badge that launches the repository at HEAD, and it points to an examples directory of Jupyter notebooks. For the evaluation suite, the README's framing is that because most causal models use machine learning internally, known ML evaluations can be re-interpreted from a causal perspective to diagnose poor models. The README does not enumerate the evaluation metrics in the text provided, so check the documentation site before assuming a specific diagnostic exists.

What causallib will not do for you

The README spends a section on confounders and DAGs, and the tone there is a warning rather than a feature list. Row selection and column selection both introduce bias if done badly, and the README states that domain expert knowledge is required and cannot be fully and truly automated by algorithms. The package assumes the data provided to the model fits the criteria. There is no confounder discovery step, no sensitivity analysis described in the README, and no test that your covariate set is sufficient. A second limitation follows from the estimator families. If your treatment is continuous or your outcome is a time-to-event with censoring, the README's two-family framing does not address it. A third is the predict_proba requirement: a gradient boosting implementation without calibrated probabilities will not slot into IPW unchanged. None of these are defects in the code. They are boundaries of the method as the README describes it, and they are the places where a user is most likely to get a confident number that means less than it appears to.

How it differs from DoWhy and EconML

DoWhy, from Microsoft, starts from a causal graph and structures the analysis as four steps: model, identify, estimate, refute. Identification is explicit, and refutation is a first-class stage. causallib does not ask for a graph. It assumes identification is settled and concentrates on estimation and evaluation. EconML, also from Microsoft, leans toward heterogeneous treatment effects with specialized estimators such as causal forests and double machine learning built for that purpose. causallib's answer to heterogeneity is narrower and stated in the README: standardization models are currently the only ones able to generate individual effect estimation. The practical difference is where each library puts its weight. If your open question is whether your assumptions hold, DoWhy's refutation step is the more direct tool. If your open question is which inner learner and which weighting scheme produce the most honest effect estimate on data you already trust, causallib's modular estimator-plus-evaluation arrangement is the closer fit. The three libraries are not mutually exclusive, and the scikit-learn-compatible interface makes causallib the easiest of the three to drop into an existing pipeline.

Maintenance, releases, and the Apache-2.0 licence

The repository is not archived. The most recent release is v0.10.0, dated 2026-05-07, following v0.9.7 in July 2024 and v0.9.6 in October 2023. The gap between v0.9.6 and v0.9.7 is roughly twenty-one months, and the gap before v0.10.0 is roughly another twenty-one months. That cadence matters more than any single version number. A library that ships every two years is stable but slow to absorb changes in the scikit-learn API it depends on, and the README's reliance on fit-predict and predict_proba means upstream deprecations can surface as breakage in causallib. The project runs CI through GitHub Actions and publishes coverage through Code Climate, and it hosts a Slack workspace for questions that do not warrant a GitHub issue. The licence is Apache-2.0, a permissive licence that includes an explicit patent grant. That is the usual choice for corporate adoption, but it also means the project carries no copyleft obligation to contribute fixes back, so upstream maintenance depends on the maintainers and the community rather than on downstream users. This is a description of the licence, not legal advice; check your own organisation's policy before shipping.

Editorial conclusion

Adopt causallib if your team already writes scikit-learn pipelines, your treatment is a discrete column you can defend, and you want potential outcomes computed out-of-bag rather than a single effect number. Do not adopt it if you expect the library to select confounders or validate your DAG; the README states plainly that this requires domain expert knowledge and is not automated. Before committing, run the README's IPW snippet against load_nhefs() and confirm your chosen inner model exposes predict_proba, since the docs note some models require it.

Official sources

  1. BiomedSciAI/causallib on GitHub
  2. Issues
  3. License: Apache-2.0
  4. README
  5. Releases
Community notes

Community notes