Open In Colab

Python Banner

Causal Machine Learning

Causal inference and machine learning answer different questions. Causal inference asks whether a change in one variable produces a change in another: does A cause B, and what would happen if we intervened on A? Machine learning asks how well a pattern in the observed data predicts an outcome. The two fields meet in causal machine learning, where flexible learners estimate the nuisance pieces of a causal model — propensity scores, outcome regressions, representations — while the causal parameter itself stays identified by a design or by an explicit assumption.

This chapter uses PyCausalML, one installable Python package for that workflow. import pycausalml exposes classical estimators (honest trees and forests, uplift learners, meta-learners, double machine learning, treatment policies, and quasi-experimental designs) and re-exports the neural models from PyDeepCausalML (TARNet, DragonNet, NOTEARS, TCDF, and the rest). import pydeepcausalml still works for the deep-learning API on its own.

The sections below keep the ideas — potential outcomes, heterogeneous effects, uplift, double machine learning, and causal discovery — and name the PyCausalML class that implements each one. Later notebooks in this folder fit those classes on data.

What PyCausalML covers

Classical estimators share an scikit-learn style interface. You construct the model, call fit(X, treatment, y), and read conditional average treatment effects (CATE) back as NumPy arrays. Neural estimators use the same top-level import and add methods such as predict_cate and predict_ate.

Question PyCausalML estimator
Honest tree or forest CATE CausalTree, CausalForest, DRLearner
Uplift on a binary outcome UpliftTree, UpliftRandomForest, UpliftXGBoost
A constant effect with a confidence interval PartiallyLinearDML, InteractiveRegressionDML
Who should be treated? PolicyLearner, DRPolicyTree
A threshold, a before/after contrast, or one treated unit RegressionDiscontinuity, DifferenceInDifferences, SyntheticControl
A neural effect on i.i.d. data TARNet, CFRNet, DragonNet
Individual effects with latent confounding GANITE, CEVAE, CausalEGM
Which variables cause which NOTEARSLinear, DAGGNN, DagmaLinear, CASTLE
Which series drives which, and at what lag TCDF, DynoTEARS, NeuralGrangerCMLP
What a series would look like under do(T) CausalLSTMForecaster, counterfactual_model

Optional adapters in pycausalml.integrations call DoWhy, EconML, causal-learn, Uber CausalML, DoubleML, CausalPy, and skgrf when those libraries are installed. The tutorials in this chapter use the native estimators.

Applications of causal inference in machine learning

Standard predictors learn associations. They answer a different question once the environment changes, or once the decision is an action we have not yet taken. Causal machine learning puts potential outcomes, directed acyclic graphs, and identification strategies inside the same pipeline that fits a forest or a network. The result is an estimate of a treatment effect, a ranking of who responds, or a graph of which series drives which — not only a forecast.

The applications below are the ones implemented in PyCausalML.

Causal effect estimation with flexible nuisance models

Propensity-score matching, regression adjustment, and instrumental variables are only as good as the functions that describe how covariates enter the treatment and the outcome. When those functions are nonlinear or high-dimensional, a parametric plug-in is the wrong tool.

Double / debiased machine learning fits those nuisance functions with a learner (a ridge model, a forest, a booster, or a network), cross-fits so the same rows are not used to build the nuisance fit and the causal score, and plugs the residuals into an orthogonal estimator of the average treatment effect. Orthogonality keeps small nuisance errors from dominating the causal parameter.

In PyCausalML that estimator is PartiallyLinearDML (and LinearDML, SparseLinearDML, NonParamDML, KernelDML, CausalForestDML, InteractiveRegressionDML). The neural counterpart for an average effect with a confidence interval is NeuralDML.

Heterogeneous and individual treatment effects

An average effect answers what happens to a population. A conditional average treatment effect answers what happens for a person with covariates (X = x):

\[\tau(x) = \mathbb{E}[Y(1) - Y(0) \mid X = x]\]

Causal trees and causal forests split on that heterogeneity rather than on the outcome alone. Honest splitting keeps the partition and the effect estimates from using the same observations. Meta-learners wrap ordinary supervised models: one model (SLearner), two outcome models (TLearner), a second-stage imputation (XLearner), a residual-on-residual regression (RLearner), or a doubly robust score (DRLearner).

PyCausalML implements these as CausalTree, CausalForest, CausalSurvivalForest, InstrumentalForest, MultiArmCausalForest, and the meta-learners in pycausalml.meta_learners. Every CATE estimator exposes explain and plot_shap so the fitted surface can be read back in terms of covariates.

Uplift modeling and personalized interventions

Uplift is the incremental change in a binary (or continuous) response caused by an action: a promotion, a message, a clinical protocol. The split criteria in an uplift tree — KL divergence, Euclidean distance, chi-square, contextual treatment selection, or delta-delta-p — look for partitions where the treated and control response rates diverge.

PyCausalML provides UpliftTree with those criteria, UpliftRandomForest, UpliftXGBoost, and InteractionTree, plus Qini curves for evaluating a ranking. A related decision problem — treat or not, given a cost — is handled by PolicyLearner, DRPolicyTree, and DRPolicyForest.

Structure, shift, and “what if” questions

Predictive models drift when the distribution of covariates or the assignment policy changes. A causal graph makes that shift explicit: an intervention is a do operation on a node, not a new row in the training table.

PyCausalML learns static graphs with NOTEARSLinear, NOTEARSNonlinearMLP, DAGGNN, DagmaLinear, DagmaNonlinearMLP, and CASTLE. For multivariate series it learns lag-resolved structure with TCDF, DynoTEARS, and the neural Granger models (NeuralGrangerCMLP, NeuralGrangerCLSTM). Counterfactual trajectories use CausalLSTMForecaster, DeepSynth, CRN, and GNet. Generative models with latent confounding — CEVAE, CausalEGM, CausalGAN, CausalVAE, DSCM — sit in the same import.

Where these estimates are used

Healthcare uses CATE models to ask which patients benefit from a therapy after adjusting for who was treated. Economics and policy evaluation use double machine learning and quasi-experiments (DifferenceInDifferences, RegressionDiscontinuity, InterruptedTimeSeries, SyntheticControl, InstrumentalVariable) when a randomized trial is unavailable. Marketing uses uplift forests to spend a promotion on units whose incremental response is positive. Fairness checks use the same graphs to separate a causal path from a spurious correlation.

Assumptions that the package does not remove

No estimator in PyCausalML invents identification. Overlap (positivity), unconfoundedness or a valid instrument, and a correctly specified causal graph remain the analyst’s responsibility. The package standardizes covariates internally, records random_state for reproducibility, and returns effects in the original outcome units. It does not test whether an unmeasured confounder is absent. Sensitivity checks and domain knowledge still belong in the analysis.

Methods, and the class that implements each one

The catalog below follows the public API. Constructors store hyperparameters. fit returns self. Predictions are NumPy arrays.

Meta-learners — pycausalml.meta_learners

Meta-learners estimate ((x)) by combining ordinary supervised models.

  • SLearner — one outcome model that includes the treatment as a feature.
  • TLearner — separate outcome models for the treated and control groups; the CATE is the difference of predictions.
  • XLearner — imputes individual effects from each group and combines them with the propensity score. Useful when treatment is imbalanced.
  • RLearner — regresses outcome residuals on treatment residuals (the R-loss of Nie and Wager).
  • DRLearner — uses a doubly robust score so the CATE stays consistent if either the outcome model or the propensity model is correct.
  • DomainAdaptationLearner — adjusts the CATE when the population used for decisions differs from the sample used for fitting.
from pycausalml import DRLearner, synthetic_data

data = synthetic_data(n=1000, p=6, sigma=0.8, mode=2, random_state=0)
dr = DRLearner(learner="gbr", n_estimators=40, random_state=0)
dr.fit(data["X"], data["w"], data["y"])
cate = dr.predict(data["X"])
ate = dr.average_treatment_effect()

Tree-based models — pycausalml.tree_based_models

These estimators partition on treatment-effect heterogeneity.

  • CausalTree, CausalForest — honest trees and forests for CATE.
  • CausalSurvivalForest — heterogeneous effects on a survival outcome.
  • InstrumentalForest, BoostedIVForest — effects identified by an instrument.
  • MultiArmCausalForest, MultiArmCausalBoost — (K ) treatment arms.
  • CXGBoost — a boosted causal tree for heterogeneous effects.

Uplift splits live next door in pycausalml.uplift_learners: UpliftTree (kl, ed, chi, cts, ddp), UpliftRandomForest, UpliftXGBoost, and InteractionTree.

Double machine learning — pycausalml.double_machine_learning

For a partially linear model (Y = D + g(X) + ) and (D = m(X) + V), cross-fitted estimates of (g) and (m) are partialled out and () is estimated from the residuals. PartiallyLinearDML.effect() returns that coefficient; confidence_interval() returns a 95% interval.

Class Role
PartiallyLinearDML Constant effect, arbitrary nuisance learners
LinearDML Final stage linear in covariates
SparseLinearDML High-dimensional linear final stage
NonParamDML, KernelDML Nonlinear final stage
CausalForestDML Forest final stage for heterogeneity
InteractiveRegressionDML Treatment–covariate interactions

BayesianLinearCATE in pycausalml.bayesian_causal_inference is the Bayesian linear counterpart for a CATE surface.

Neural treatment-effect models — pydeepcausalml.effect

These classes import from pycausalml and from pydeepcausalml. Pass device="cpu", "cuda", or "mps", or leave device=None to auto-select.

Class Role
TARNet Shared representation and two outcome heads
CFRNet TARNet plus representation balancing
DragonNet Propensity head and targeted regularization
NeuralDML Cross-fitted neural double ML for the ATE
GANITE GAN-based individual effects
CEVAE Variational autoencoder with a latent confounder
from pycausalml import DragonNet
from pydeepcausalml.datasets import make_confounded_data

df = make_confounded_data(n=2000, random_state=0)
X = df[["age", "education", "prior_income"]].values
est = DragonNet(epochs=50, random_state=0).fit(X, df["treatment"].values, df["outcome"].values)
est.predict_ate(X)

Generative models and structure learning

Generative models (pydeepcausalml.generative) encode latent confounding or a structural assignment: CausalEGM, CausalGAN, CausalDiscrepancyVAE, IVAE, CausalVAE, and DSCM.

Static structure learning (pydeepcausalml.discovery) returns an adjacency matrix. In this package, A[i, j] = 1 means (X_j) causes (X_i) (rows are effects, columns are causes).

  • NOTEARSLinear, NOTEARSNonlinearMLP, NOTEARSNonlinearSobolev
  • DAGGNN
  • DagmaLinear, DagmaNonlinearMLP
  • CASTLE
  • DynoTEARS for lag-resolved series

The factory causal_structure_ml("dagma_linear") (and the other method names) builds the same estimators.

Time series, policies, and quasi-experiments

Granger-style discovery. NeuralGrangerCMLP, NeuralGrangerCLSTM, NeuralGrangerEconomySRU, NeuralRelationalInference, and GrangerLSTM. The factory is neural_granger_model("cmlp").

Attention, recurrent, and graph models. TCDF reports edges and delays. CausalTransformer, TFTNet, CausalLSTM, CausalLSTMForecaster, RETAIN, and InterventionAwareRNN model temporal dependence. GVAR, CausalGNN, and CUTS use a graph over series.

Counterfactual series. DeepSynth, CRN, GNet, DeepSCM, and DECI. The factory is counterfactual_model("crn").

Policies. PolicyLearner, DRPolicyTree, and DRPolicyForest turn a CATE into a treatment rule.

Quasi-experiments. DifferenceInDifferences, RegressionDiscontinuity, InterruptedTimeSeries, InstrumentalVariable, and SyntheticControl.

Install and import

From this repository:

pip install -e ".[dev]"

PyTorch is a dependency because the neural models ship in the same distribution. Plotting and the optional backends are extras: pip install -e ".[plot]" and pip install -e ".[dowhy,econml,causallearn,uber,doubleml,causalpy,skgrf,shap,boost]".

The next cell adds src/ to the path when the notebook is run from a checkout that has not been installed yet, then prints the package version.

Code
import sys
from pathlib import Path

here = Path.cwd().resolve()
for candidate in (here, here.parent, here.parent.parent):
    src = candidate / "src"
    if (src / "pycausalml").is_dir() and str(src) not in sys.path:
        sys.path.insert(0, str(src))
        break

import pycausalml
from pycausalml.integrations import available_backends

print("pycausalml", pycausalml.__version__)
print("backends", available_backends())

A short fit

synthetic_data draws a treatment, an outcome, and covariates with a known heterogeneous effect. DRLearner estimates the CATE. make_linear_treatment draws a constant effect so PartiallyLinearDML can report that effect and a confidence interval.

Code
from pycausalml import DRLearner, PartiallyLinearDML, synthetic_data
from pycausalml.data import make_linear_treatment

data = synthetic_data(n=1000, p=6, sigma=0.8, mode=2, random_state=0)
dr = DRLearner(learner="gbr", n_estimators=40, random_state=0).fit(
    data["X"], data["w"], data["y"]
)
print("CATE (first 5 rows):", dr.predict(data["X"][:5]))
print("ATE:", dr.average_treatment_effect())

linear = make_linear_treatment(n=800, tau=2.0, random_state=0)
dml = PartiallyLinearDML(model_y="ridge", random_state=0).fit(
    linear["X"], linear["w"], linear["y"]
)
print("DML effect:", dml.effect())
print("95% CI:", dml.confidence_interval())

How the rest of this chapter is organized

Folder PyCausalML module
Tutorials/05_01_Tree_Based_Models pycausalml.tree_based_models
Tutorials/05_02_Meta_Learners pycausalml.meta_learners
Tutorials/05_03_Uplift_Learners pycausalml.uplift_learners
Tutorials/05_04_DoubleML pycausalml.double_machine_learning
Tutorials/05_05_DeepCausalML pydeepcausalml (effects, generative models, structure learning, time series)

Interpretation of a fitted CATE is shared: explain_cate, or model.explain and model.plot_shap on any classical CATE estimator. The default explainer is an interventional permutation attribution and does not require the shap package.

Summary

Causal machine learning uses a learner where a causal formula needs a flexible function, and it keeps the causal parameter — an average effect, a CATE, an uplift, a policy, or an edge in a graph — tied to an identifying assumption. PyCausalML puts those estimators in one import: trees and forests, uplift models, meta-learners, double machine learning, policies, quasi-experiments, and the PyDeepCausalML neural catalog.

Start with DRLearner or CausalForest when the question is who benefits, with PartiallyLinearDML when the question is a single effect and a confidence interval, with UpliftRandomForest when the outcome is a response to an action, and with DragonNet or NOTEARSLinear when the data call for a neural effect or a learned graph. The notebooks that follow fit each of those classes.

Resources

Package

  • PyCausalML source and API: the src/pycausalml and src/pydeepcausalml packages in this repository, and the README sections Choosing an estimator, Classical estimators, and Deep learning models.
  • Worked script: examples/quickstart.py.

Books and courses

  • Chernozhukov, Hansen, Kallus, Spindler, and Syrgkanis. Applied Causal Inference Powered by ML and AI (causalml-book.org). Double/debiased machine learning, with code in Python and R.
  • Hernán and Robins. Causal Inference: What If. Potential outcomes and identification.
  • Peters, Janzing, and Schölkopf. Elements of Causal Inference. Causal discovery from a machine-learning perspective.
  • Brady Neal. Introduction to Causal Inference. Heterogeneous effects from an ML point of view.

Papers behind the classes in this package

  • Athey and Imbens (2016), honest causal trees; Athey, Tibshirani, and Wager (2019), generalized random forests.
  • Künzel, Sekhon, Bickel, and Yu (2019), meta-learners; Nie and Wager (2021), the R-learner.
  • Chernozhukov et al. (2018), double/debiased machine learning.
  • Shalit, Johansson, and Sontag (2017), TARNet and CFRNet; Shi, Blei, and Veitch (2019), DragonNet.
  • Yoon, Jordon, and van der Schaar (2018), GANITE; Louizos et al. (2017), CEVAE.
  • Zheng et al. (2018), NOTEARS; Yu et al. (2019), DAG-GNN; Bello et al. (2022), DAGMA.
  • Nauta, Bucur, and Seifert (2019), TCDF; Tank et al. (2021), neural Granger causality.
Back to top