jordancheney89/causality
      
Causal Inference Dashboard
Interactive Dash app for comparing a suite of causal measurement approaches using a publicly available randomised marketing experiment as an example (Hillstrom, 2008).
Live demo: Hugging Face Space
This project provides a dashboard to:
- estimate average treatment effects (ATE) with uncertainty
- inspect heterogeneity and targeting value
- show where each method agrees and disagrees, and what assumptions drive the result
What this dashboard shows
Teams might ask two different questions:
- "Did the campaign work on average?" (causal effect / ATE)
- "Who should we target next?" (HTE / uplift policy)
This dashboard puts both views side-by-side so the methodological choices and any business implications are easily comparable.
Methods Covered
Dataset
Source: MineThatData Email Analytics (Hillstrom)
Randomised experiment across ~64,000 customers:
- Men's, Women's and Control (split roughly equal-sized three ways)
- Primary outcome: 2-week post-campaign spend (USD)
- Key covariates: recency, history, mens/womens indicators, zip code, newbie, channel
Quick Start
Dependencies are managed with [uv](https://docs.astral.sh/uv/).
Requirements
- uv installed
- Python 3.13+
Install
From the project root:
uv syncThis creates .venv (if needed) and installs the locked dependency set.
Run
uv run app.pyOpen http://localhost:8050.
First-run behavior
- First run precomputes models and caches results in
.cache/results.pkl. - Subsequent runs load from cache and start quickly.
- Depending on machine speed, initial build can take several minutes.
Force recompute
- Delete
.cache/results.pkl, or setUSE_CACHE = Falseincausal_utils.py. - Restart the app once to rebuild the cache.
- Set
USE_CACHEback toTrueafter a deliberate rebuild (optional, deleting the pickle has the same effect ifUSE_CACHEstaysTrue).
Hugging Face Spaces (Docker)
Live Space: huggingface.co/spaces/jordancheney89/causality
This repo includes a `Dockerfile` configured for the Docker Spaces SDK
Methodology Notes and Caveats
- The underlying dataset is randomized, so causal identification of average effects comes from random assignment.
- Covariate-adjusted analyses are included for precision and interpretability, propensity matching is included as a pedagogical workflow.
- Average CATE is reported with a bootstrap interval, though that interval is estimation-conditional and reads as a lower bound on the true uncertainty for high-stakes targeting.
- Propensity matching (PSM) is included as a demo workflow for non-randomised data, and isn't used as a headline estimate for this dashboard.
Results Snapshot
- Men's email lifts two-week spend by about $0.77 per recipient (95% CI $0.50 to $1.05), Women's by about $0.42 ($0.17 to $0.67).
- The methods agree: Bayesian, OLS and both uplift learners all land between $0.74 and $0.79 (Men's) and $0.42 and $0.45 (Women's).
- The lift is a conversion effect. The emails roughly double the share of customers who buy (1.25% / 0.88% vs 0.57% in control) while spend per buyer stays around $114.
- Both uplift rankings beat random targeting (permutation p < 0.002), and the policy view turns the ranking plus a send cost and margin into an optimal mailing share.
Project Structure
.
โโโ Dockerfile # Hugging Face Spaces (Docker SDK), gunicorn on port 7860
โโโ .dockerignore # Smaller build context (excludes .venv, caches of dev tools)
โโโ app.py # Thin entrypoint: Dash app, theme registration, layout, callback wiring
โโโ causal_utils.py # Data prep, caching, and all causal estimation logic
โโโ dashboard/
โ โโโ theme.py # Design tokens, Plotly template, shared style dicts
โ โโโ data.py # Loads cache โ exposes RESULTS, DF, PSM, BAYESIAN, UPLIFT, OLS
โโโ pages/ # Dash Pages route registration
โ โโโ overview.py # /
โ โโโ bayesian.py # /bayesian
โ โโโ ols.py # /ols
โ โโโ uplift.py # /uplift
โ โโโ psm.py # /psm
โ โโโ comparison.py # /comparison
โโโ layouts/
โ โโโ shell.py # Masthead + section nav + Dash Pages container
โ โโโ components.py # Reusable UI helpers
โ โโโ overview.py # Overview layout
โ โโโ psm.py # PSM layout
โ โโโ bayesian.py # Bayesian A/B layout
โ โโโ uplift.py # Uplift / HTE layout
โ โโโ ols.py # Multi-Arm OLS layout
โ โโโ comparison.py # Method Comparison layout
โโโ callbacks/
โ โโโ __init__.py # register_callbacks(app)
โ โโโ psm.py # PSM callbacks
โ โโโ bayesian.py # Bayesian A/B callbacks
โ โโโ uplift.py # Uplift / HTE callbacks
โ โโโ ols.py # Static OLS figure builder
โ โโโ comparison.py # Method Comparison callbacks
โโโ figures/
โ โโโ overview.py # Static Plotly helpers for Overview tab
โโโ content/
โ โโโ methodology.py # Long-form copy separated from layout code
โโโ assets/
โ โโโ style.css # Global styles (Dash serves /assets automatically)
โโโ .cache/ # Precomputed outputs (e.g. results.pkl)
โโโ pyproject.toml
โโโ uv.lock
โโโ .python-version
โโโ README.mdRoadmap
- Add data ingestion wizard
License
MIT. See LICENSE.
