Causalis
Robust causal inference for experiments and observational studies in Python, organized around scenarios (e.g., Classic RCT, CUPED, Unconfoundedness) with a consistent fit() → estimate() workflow.
- 📚 Documentation & notebooks: https://causalis.causalcraft.com/
- 🔎 API reference: https://causalis.causalcraft.com/api-reference
Why Causalis?
Causalis focuses on:
- Scenario-first workflows (you pick the study design; Causalis provides best-practice defaults).
- Extensive robustness tests that reveal issues in the study design or model specification
- Pydantic data contracts
- An advanced DGP (Data Generating Process) with heterogeneous treatment effects, latent variables, and correlated confounders
- A website with notebooks based on real-world cases
Installation
Recommended
pip install causalis
Quickstart: Classic RCT (difference in means + inference)
from causalis.dgp import generate_classic_rct_26
from causalis.scenarios.classic_rct import DiffInMeans, check_srm
# Synthetic RCT data as a validated CausalData object
data = generate_classic_rct_26(seed=42, return_causal_data=True)
# Optional: Sample Ratio Mismatch check
srm = check_srm(data, target_allocation={0: 0.5, 1: 0.5}, alpha=1e-3)
print("SRM detected?", srm.is_srm, "p=", srm.p_value, "chi2=", srm.chi2)
# Estimate treatment effect with t-test inference (or bootstrap / conversion_ztest)
result = DiffInMeans().fit(data).estimate(method="ttest", alpha=0.05)
result.summary()
Quickstart: Observational study (Unconfoundedness / DML IRM)
from causalis.scenarios.unconfoundedness.dgp import generate_obs_hte_26
from causalis.scenarios.unconfoundedness import IRM
from causalis.data_contracts import CausalData
causaldata = generate_obs_hte_26(return_causal_data=True, include_oracle=False)
from causalis.scenarios.unconfoundedness import IRM
model = IRM().fit(causaldata)
result = model.estimate(score='ATTE')
result.summary()
Binary sensitivity protocol for observational DML/IRM
Pre-specify a practically meaningful effect boundary and one or more
domain-justified groups of observed pre-treatment confounders. The primary
decision uses element-based long/short gain statistics for the benchmark
group. Its r2_y, r2_d, and rho are calibrated jointly from the outcome
variance, Riesz-representer variance, and actual effect shift. The 2× strength
and forced rho=1 scenarios are reported as secondary stress tests.
from causalis.scenarios.unconfoundedness.refutation import run_sensitivity_protocol
# Example only: replace with a domain-justified, pre-specified group.
primary_group = list(causaldata.confounders[:2])
protocol = run_sensitivity_protocol(
model,
causaldata,
benchmark_groups={"primary_domain_benchmark": primary_group},
decision_threshold=0.0, # replace with the minimum practical effect
direction="auto", # default: infer direction relative to the threshold
preconditions_passed=True, # causal set, overlap, nuisance quality, stability
)
print(protocol["status"])
print(protocol["summary"])
protocol["primary"]
protocol["stress"]
protocol["adversarial"]
PASS means every primary benchmark's bias-aware confidence interval remains
strictly beyond decision_threshold in the requested direction. RV and
RVa are reported as robustness diagnostics, not compared with universal
cutoffs. An empty benchmark set, failed external preconditions, unavailable
sensitivity elements, or strengths outside the finite sensitivity domain
produce FAIL.
By default, direction="auto" selects positive when the original estimate is
at or above decision_threshold, and negative otherwise. It uses this same
direction for every scenario and returns it in protocol["direction"], with
an inference warning in protocol["warnings"]. For a negative estimate at a
zero threshold, every primary CI must have ci_upper < 0; touching or crossing
zero still fails. Thresholds retain their supplied sign, and an estimate equal
to the threshold does not pass. Use explicit direction="positive" or
direction="negative" for a pre-specified directional claim; these choices are
never overridden. Significance before sensitivity analysis alone does not
guarantee a pass.
Benchmark boundary handling matches DoubleML: raw cf_y and cf_d are
clipped to [0, 1]. If either long/short gain is not strictly positive,
primary and stress use rho=sign(theta_short-theta_long); the adversarial
scenario still forces rho=1. protocol["benchmarks"] retains raw gains,
clipping/fallback flags, long/short elements, and warnings for auditability.
In particular, a negative cf_d_raw becomes a numerical cf_d=0 boundary
benchmark rather than a missing scenario.
Pick your scenario
| Scenario | Estimator | Assumptions |
|---|---|---|
| Classic RCT | Difference in means (ttest, ztest, welch_permutation_t_test) | Random assignment, no sample ratio mismatch, SUTVA |
| CUPED | CUPED-adjusted difference in means with Lin specification | Random assignment, no sample ratio mismatch, SUTVA, valid pre-period metrics |
| Unconfoundedness | DML IRM | Unconfoundedness, Overlap, SUTVA, No leakage, Score stability |
| GATE | DML IRM (GATE and GATET) | Same assumptions as unconfoundedness, plus meaningful pre-specified or validated subgroup definitions. |
| Multi Unconfoundedness | Multi DML IRM | Unconfoundedness, Multi class Overlap, SUTVA, No leakage, Score stability |
| Synthetic Control | ASCM | No interference / spillovers, No anticipation, The treated unit’s untreated outcome path is well approximated by the donor pool |
| Difference in Difference | CallawaySantAnnaDID | Parallel trends, no anticipation, stable group composition, no spillovers between treated and control groups. |
| IV | DML IV | First-stage strength, Reduced form, Instrument balance by Z, Instrument propensity / predictability |
| Uplift / CATE scoring | DML IRM (CATE) | Identified treatment effects from randomized or unconfounded data, overlap, calibrated individual-level predictions. |
Introduction to Causal Inference: guide
See scenario notebooks: https://causalis.causalcraft.com/explore-scenarios
Contributing guidelines
Maintainers
References
https://github.com/DoubleML/doubleml-for-py
Search terms / supported methods
Causalis covers methods often searched as:
- causal inference Python
- causal machine learning Python
- treatment effect estimation
- A/B testing Python
- randomized controlled trial analysis
- CUPED Python
- Double Machine Learning Python
- DML / IRM
- CATE estimation
- uplift modeling
- propensity score diagnostics
- synthetic control Python
- difference-in-differences Python
Release files for causalis 1.0.7
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| causalis-1.0.7.tar.gz | 30.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| causalis-1.0.7-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 30.6 MB
Release files / causalis-1.0.7.tar.gz
| Download URL | causalis-1.0.7.tar.gz |
|---|---|
| Size | 30.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
e04eb0c194ff6d517fa624061255c7436e0132c9ac5a71ae28affa48ce229a3e
|
|
BLAKE2b-256 checksum How to use checksums |
56cca9b2711e3105852440d7b875b41d3f15feacbc5e8b650de1d97f47c1f0aa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / causalis-1.0.7-py3-none-any.whl
| Download URL | causalis-1.0.7-py3-none-any.whl |
|---|---|
| Size | 455.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
349ee500a76f698b67ff473a40668085d06d7e35ceaebf0d48c61644f6921255
|
|
BLAKE2b-256 checksum How to use checksums |
0b3d9bc70e6bd1f75e465ce3ba94bd57656c5f1c659762de158adf2c05d4e929
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency log