Skip to content
13 changes: 10 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@ research [[1]](#Literature). It provides a standard interface that allows user t

# Documentation

Documentation is available at:
Documentation is available at https://causalml.readthedocs.io/. Good places to start:

https://causalml.readthedocs.io/en/latest/about.html
* [Estimating and Validating Heterogeneous Treatment Effects](https://causalml.readthedocs.io/en/latest/tutorial.html): an end-to-end walkthrough that trains one estimator per family and shows how to decide which one to believe
* [Choosing an Estimator](https://causalml.readthedocs.io/en/latest/choosing_an_estimator.html): a decision path and capability matrix over the estimators
* [FAQ](https://causalml.readthedocs.io/en/latest/faq.html): answers to common installation and usage questions


# Installation
Expand All @@ -54,6 +56,11 @@ Example notebooks are available at:
https://causalml.readthedocs.io/en/latest/examples.html


# Benchmark Datasets and Leaderboard

CausalML ships loaders for the standard causal inference benchmarks (LaLonde, IHDP, Twins) with SHA256-verified downloads, plus the ground-truth metrics (PEHE, ATE error, policy risk) they enable. See the [benchmark datasets](https://causalml.readthedocs.io/en/latest/datasets.html) page for each dataset's provenance and terms, and the [leaderboard notebook](https://causalml.readthedocs.io/en/latest/examples/benchmark_leaderboard.html), which regenerates every published number end to end.


# Contributing

We welcome community contributors to the project. Before you start, please read our [code of conduct](https://github.com/uber/causalml/blob/master/CODE_OF_CONDUCT.md) and check out [contributing guidelines](./CONTRIBUTING.md) first.
Expand All @@ -72,7 +79,7 @@ This project is licensed under the Apache 2.0 License - see the [LICENSE](https:
# References

## Documentation
* [Causal ML API documentation](https://causalml.readthedocs.io/en/latest/about.html)
* [Causal ML API reference](https://causalml.readthedocs.io/en/latest/causalml.html)

## Workshops, Talks, and Publications
* (Workshop) [3rd Workshop on Causal Inference and Machine Learning in Practice](https://causal-machine-learning.github.io/kdd2025-workshop/) at KDD 2025
Expand Down
Binary file added docs/_static/img/intro_confounding_sim.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/tutorial_gain.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/tutorial_overlap.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/_static/img/tutorial_toc.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
139 changes: 139 additions & 0 deletions docs/choosing_an_estimator.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
=====================
Choosing an Estimator
=====================

CausalML implements many estimators because no single one dominates: they
differ in the outcome and treatment types they accept, the data they are
designed for, and what they report. This page maps a problem to a shortlist.
The mathematics of each method lives in the :doc:`methodology`; the API details
live in the :doc:`API Reference <causalml>`.

Start from the data
===================

**Was the treatment randomized?**

* **Yes, and compliance was perfect.** Any estimator below applies, and the
assignment probability is known -- pass it as ``p`` instead of estimating it.
For a binary conversion outcome where the goal is targeting segments or
interpretable rules, start with the uplift trees. For per-unit CATE
estimates with confidence intervals, start with the meta-learners.

* **Yes, but some units did not comply.** The randomized assignment is an
instrument for the treatment actually received. Use the
:ref:`DRIV learner <methodology:Doubly Robust Instrumental Variable (DRIV) learner>`
(``BaseDRIVLearner``) to estimate the effect on compliers, or
:ref:`2SLS <methodology:2-Stage Least Squares (2SLS)>` for a linear model.

* **No -- the data are observational.** Estimation requires that every
confounder (a variable driving both treatment and outcome) is measured, and
that treated and untreated units overlap (see
:ref:`Checking Overlap <validation:Checking Overlap>`). Prefer the
estimators that model the treatment assignment explicitly: the
:ref:`X-Learner <methodology:X-Learner>`,
:ref:`R-Learner <methodology:R-Learner>` and
:ref:`DR learner <methodology:Doubly Robust (DR) learner>` all accept a
propensity score ``p`` and estimate one internally when it is omitted.
Validate with :doc:`sensitivity analysis <validation>` afterwards.

* **No, and an important confounder is unmeasured.** With an instrument, use
the IV estimators above. With proxy variables for the hidden confounder,
:ref:`CEVAE <methodology:CEVAE>` models it as a latent variable. Without
either, no estimator in this package (or any other) identifies the effect.

**What do you need out of the model?**

* **Only the average effect (ATE)** -- :ref:`TMLE
<methodology:Targeted maximum likelihood estimation (TMLE) for ATE>`,
:ref:`IPTW <methodology:Inverse probability of treatment weighting>`,
:ref:`matching <methodology:Matching>`, or any meta-learner's
``estimate_ate()``.
* **Per-unit effects (CATE)** -- meta-learners, causal trees and forests, or
the neural models.
* **Segments and rules you can read** -- uplift trees, with
:ref:`visualization <interpretation:Uplift Tree Visualization>`.
* **Who to treat under constraints** -- estimate CATE first, then use
``PolicyLearner`` or the
:ref:`value optimization methods <methodology:Value optimization methods>`.

Capability matrix
=================

.. list-table::
:header-rows: 1
:widths: 26 17 15 16 16 10

* - Estimator (classes)
- Outcome type
- Treatment
- Observational data
- Uncertainty
- Extra install
* - S/T/X/R meta-learners (``BaseSRegressor`` ... ``BaseRClassifier``)
- continuous (``*Regressor``) or binary (``*Classifier``)
- binary or multiple discrete
- yes; X/R use a propensity score
- ATE CI; bootstrap CATE CI
- --
* - DR learner (``BaseDRRegressor``/``BaseDRClassifier``)
- continuous or binary
- binary or multiple discrete
- yes, doubly robust
- ATE CI; bootstrap CATE CI
- --
* - DRIV learner (``BaseDRIVLearner``)
- continuous
- binary, with an instrument
- yes, given an instrument
- ATE CI; bootstrap CATE CI
- --
* - Uplift trees (``UpliftTreeClassifier``, ``UpliftRandomForestClassifier``)
- binary or multi-class
- binary or multiple discrete
- designed for randomized data
- --
- --
* - Causal trees (``CausalTreeRegressor``, ``CausalRandomForestRegressor``)
- continuous
- binary
- yes
- ATE CI (tree); per-prediction variance (forest)
- --
* - ``DragonNet``
- continuous or binary
- binary
- yes
- --
- ``tf`` or ``jax``
* - ``CEVAE``
- continuous or binary
- binary
- yes, with proxies for a hidden confounder
- --
- ``torch`` or ``jax``
* - 2SLS (``IVRegressor``)
- continuous
- continuous or binary, with an instrument
- yes, given an instrument
- coefficient SE
- --
* - ``TMLELearner`` (ATE only)
- continuous
- binary
- yes, with a propensity score
- ATE CI
- --

How the uncertainty is computed, per estimator, is cataloged in
:doc:`inference`.

Two rules of thumb
==================

* **Start simple, then justify complexity.** A T-learner with a linear base
learner is a transparent baseline; adopt a more flexible estimator when
held-out evaluation (:doc:`validation`) shows it ranks units better.
* **Do not choose by in-sample fit.** CATE models cannot be scored against an
observed label. Compare candidates with the validation losses and ranking
metrics on held-out data, as described in
:ref:`Model Selection with Validation Losses <validation:Model Selection with Validation Losses>`.
8 changes: 7 additions & 1 deletion docs/datasets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ Results on IHDP are reported as a mean and standard error across replications::

scores = [pehe(fetch_ihdp(replication=r).tau, predict(r)) for r in range(100)]

A single replication is not comparable to a published IHDP number.
A single replication is not comparable to a published IHDP number. Neither,
exactly, is a mean over this file: the same release also exists in a
1,000-replication version, and that is what the published tables of the CEVAE
:cite:`louizos2017causal` and DragonNet :cite:`shi2019adapting` papers
aggregate over (with the 672 further split 63/27 into train and validation).
The data-generating process and split geometry match; the replication count
does not.

Source: the `clinicalml/cfrnet <https://github.com/clinicalml/cfrnet>`_ lineage
(MIT), files hosted at ``fredjo.com``.
Expand Down
93 changes: 93 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
==========================
Frequently Asked Questions
==========================

Importing CausalML fails with an XGBoost error on macOS
-------------------------------------------------------

``xgboost`` and ``lightgbm`` need the OpenMP runtime (``libomp``), which macOS
does not ship. Since v0.16, the import error names the fix directly: install it
with ``brew install libomp`` or ``conda install -c conda-forge llvm-openmp``,
then retry. See :ref:`Installation <installation:Installation>`.

Downloading a benchmark dataset fails with ``CERTIFICATE_VERIFY_FAILED``
------------------------------------------------------------------------

The dataset loaders (:doc:`datasets`) download over HTTPS with Python's
standard library, which needs a CA certificate bundle. Some Python
installations -- notably the python.org macOS installers -- do not wire one up
by default. Run the ``Install Certificates.command`` that ships with the
python.org installer, or point Python at the ``certifi`` bundle:

.. code-block:: bash

export SSL_CERT_FILE=$(python -c "import certifi; print(certifi.where())")

My causal tree results changed after upgrading
----------------------------------------------

``CausalTreeRegressor`` and ``CausalRandomForestRegressor`` estimate leaves
honestly by default since #584: the tree structure is grown on one half of the
sample and leaf values are re-estimated on the other, which changes fitted
trees, leaf values and CATE estimates without any code edit. Pass
``honesty=False`` to reproduce the previous behavior, and see
:ref:`Honest estimation <methodology:Honest estimation>` for why the new
default is better on most data.

``UpliftRandomForestClassifier`` got slower after upgrading
-----------------------------------------------------------

Its default changed from ``n_jobs=-1`` (all cores) to ``n_jobs=None`` (one
worker) in #991, because each concurrent tree fit holds its own working set:
peak memory grew with the machine's core count -- 8.8x the input array at
``n_jobs=-1`` on 10 cores versus 1.4x single-threaded, in the benchmark that
motivated the change. Fitted models are identical either way. Pass
``n_jobs=-1`` explicitly to restore the previous speed if you have the memory.

My Qini or AUUC score is negative
---------------------------------

A negative score means the model's ranking performed *worse* than treating
units in random order on that data -- units it ranked as high-benefit gained
less than average. Before concluding the model is bad, compute the score on
held-out data with ``return_ci=True``: on small samples the confidence
interval is often wide enough that a negative point estimate is
indistinguishable from zero. The :doc:`validation` page gives the full
evaluation workflow, and Step 6 of the :doc:`tutorial` shows a real example.

My propensity scores pile up near 0 or 1
----------------------------------------

That signals an overlap (positivity) problem: some units essentially always or
never receive treatment given their covariates, so their counterfactual is not
represented in the data. Estimators that weight by inverse propensity become
unstable there. Common responses are trimming the non-overlapping region or
clipping the scores away from the boundaries -- and reconsidering whether the
treatment is really variable for those units. See
:ref:`Checking Overlap <validation:Checking Overlap>`.

The Twins dataset's outcome looks like earnings, not mortality
--------------------------------------------------------------

The Twins benchmark encodes survival as ``9999``, so mortality is
``outcome < 9999`` -- reading the column as a number produces a mean near
8,000 and every downstream statistic is garbage. The loader's docstring and
:doc:`datasets` record this; the loader's tests pin it.

My IHDP results differ across replications more than expected
-------------------------------------------------------------

Each IHDP replication draws its own train/test split of the same 747 units,
so rows are **not** aligned across replications -- averaging
predictions row-wise across replications compares different children. Evaluate
each replication independently and aggregate the metric, as the
:doc:`benchmark leaderboard <examples/benchmark_leaderboard>` does.

Do I need TensorFlow, PyTorch or JAX?
-------------------------------------

Only for the neural estimators: ``DragonNet`` needs the ``tf`` or ``jax``
extra and ``CEVAE`` needs ``torch`` or ``jax``. Everything else -- meta-learners,
trees, IV, evaluation -- runs without any of them. Install via
``pip install causalml[tf]`` etc.; see
:ref:`Installation <installation:Installation>`.
6 changes: 5 additions & 1 deletion docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ Getting Started
===============

What CausalML is, an introduction to causal machine learning for readers new to
it, how to install the package, and a tour of the API in runnable snippets.
it, how to install the package, a tour of the API in runnable snippets, an
end-to-end walkthrough of estimating and validating heterogeneous treatment
effects on a benchmark, and answers to common questions.

.. toctree::
:maxdepth: 2
Expand All @@ -12,3 +14,5 @@ it, how to install the package, and a tour of the API in runnable snippets.
intro
installation
quickstart
tutorial
faq
86 changes: 86 additions & 0 deletions docs/inference.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
==========================
Uncertainty Quantification
==========================

Every number CausalML produces is an estimate, and most of them can carry a
confidence interval. This page catalogs, per estimator family and per metric,
what uncertainty measure is available, how it is computed, and how to request
it. It consolidates an API surface that is otherwise spread across the
individual classes.

Average treatment effects
=========================

**Meta-learners.** ``estimate_ate()`` returns the triple ``(ate, lb, ub)``.
The default interval is analytic, based on the lower-bound formula (7) of
:cite:`imbens2009recent`; passing ``bootstrap_ci=True`` (with ``n_bootstraps``
and ``bootstrap_size``) replaces it with a bootstrap interval. The
:ref:`DRIV learner <methodology:Doubly Robust Instrumental Variable (DRIV) learner>`
follows the same interface.

**TMLE.** ``TMLELearner.estimate_ate(..., return_ci=True)`` reports the ATE
with a confidence interval; :ref:`the methodology section
<methodology:Targeted maximum likelihood estimation (TMLE) for ATE>` describes
the estimator.

**Causal trees.** ``CausalTreeRegressor.estimate_ate()`` also returns
``(ate, lb, ub)``.

CATE estimates
==============

**Meta-learners.** ``fit_predict(..., return_ci=True)`` returns per-unit CATE
estimates with lower and upper bounds from a bootstrap over refits:
``n_bootstraps`` controls the number of refits and ``bootstrap_size`` the
resample size, so the cost is roughly ``n_bootstraps`` times the single fit.

**Causal forests.** ``CausalRandomForestRegressor.calculate_error(X_train,
X_test)`` returns an unbiased sampling variance for each prediction, computed
with the infinitesimal jackknife of `Wager, Hastie and Efron (2014)
<https://arxiv.org/abs/1311.4555>`_ as implemented in `forestci
<https://github.com/scikit-learn-contrib/forest-confidence-interval>`_.

**Uplift trees.** ``UpliftTreeClassifier`` and
``UpliftRandomForestClassifier`` do not report uncertainty for their
estimates.

Evaluation metrics
==================

The evaluation functions accept ``return_ci=True`` and then return a DataFrame
with the score, its bootstrap standard error and confidence interval bounds
per model column (``n_bootstrap``, ``alpha`` and ``random_state`` control the
bootstrap). Pass ``random_state`` whenever the numbers will be reported: the
bootstrap otherwise draws from the global NumPy state and will not reproduce.

.. list-table::
:header-rows: 1
:widths: 30 40 30

* - Function
- Uncertainty reported
- Notes
* - ``auuc_score``
- bootstrap SE and CI
- no p-value by design; compare models by CI overlap
* - ``qini_score``
- bootstrap SE, CI and p-value
- p-value tests ranking better than random
* - ``rate_score``
- half-sample bootstrap SE, CI and p-value
- the heterogeneity test; see :ref:`RATE <methodology:RATE>`
* - ``dr_score`` / ``plug_in_t_score``
- bootstrap SE and CI on the loss
- lower loss is better; see
:ref:`Model Selection with Validation Losses <validation:Model Selection with Validation Losses>`

What an interval does and does not cover
========================================

These intervals quantify sampling uncertainty under each estimator's
assumptions -- most importantly unconfoundedness. They say nothing about bias
from an unmeasured confounder; that question belongs to
:ref:`sensitivity analysis <validation:Validation with Sensitivity Analysis>`.
And a per-unit CATE interval that excludes zero is not yet evidence of
targetable heterogeneity across units -- that claim needs the held-out tests
in :doc:`validation`.
Loading