Causal inference & uplift modeling
Your ranker predicts P(click | shown). Your business wants to know whether showing this notification, ad, or coupon actually changed what the user did — versus doing nothing. Those are different questions, and the gap between them is the entire lesson. Predicting an outcome is not the same as estimating the effect of an intervention.
The gap: prediction vs intervention
Every model so far in this series fits a conditional expectation — E[Y | X], the click rate of items given they were shown. That is a predictive quantity, and for picking the top item at a fixed slot it is usually enough (lesson 08 · Evaluation defends exactly that). But a huge class of decisions is not "which item is best" — it is "does doing this thing change behavior at all?" Send the push or stay silent. Spend the coupon or save it. Re-rank this feed or leave the default. These are interventions, and the quantity you need is a counterfactual contrast: behavior under treatment minus behavior without it.
The trap is that a high-P(convert) user and a high-uplift user are often different people. The user who would have bought anyway scores high on your conversion model and is exactly the user a coupon wastes money on. The whole field of causal inference and uplift modeling exists to stop you from confusing the two.
Potential outcomes — the Rubin framework
Fix a unit (a user). Define two potential outcomes: Y(1) is what happens if we treat them (send the push), Y(0) is what happens if we don't. The individual treatment effect is
τ_i = Y_i(1) − Y_i(0).
Here is the fundamental problem of causal inference: for any single user you observe at most one of Y_i(1) and Y_i(0) — you either sent the push or you didn't; the other is a counterfactual that never happened. τ_i is never directly observable. Causal inference is the art of recovering averages of these effects despite never seeing a single one.
So we step down from the individual to estimable averages:
- ATE — average treatment effect over the whole population: ATE = E[Y(1) − Y(0)]. "Does the campaign help on average?"
- CATE / HTE — conditional average treatment effect, a.k.a. heterogeneous treatment effect: τ(x) = E[Y(1) − Y(0) | X = x]. "For this kind of user, how much does it help?" CATE is uplift. Same object, two names — the ML community says "uplift," the stats community says "CATE."
The ATE answers "should the campaign exist." The CATE answers "whom do I target," which is the question that actually moves money. The rest of this lesson is two halves: how to get an unbiased ATE/CATE when you can randomize, and how to approximate one when you can't.
Why the A/B test is the gold standard
Randomization is the one move that makes causal inference trivial. If a coin decides who is treated, then treatment assignment T is independent of every confounder — observed or not — so the treated and control groups are statistically identical except for the treatment. The naive difference of group means is then unbiased for the ATE:
ÂTE = Ȳ_treated − Ȳ_control.
This is exactly the A/B test from lesson 08 · Evaluation, now read through a causal lens: the experiment manufactures the counterfactual by holding out a randomized control. No randomization → confounding → the difference of means estimates correlation, not effect.
Uplift = targeting the effect, not the outcome
Cross two binary facts about a user — would they convert if treated? would they convert if not treated? — and you get the four canonical response types. This 2×2 is the most important picture in the lesson:
- Persuadables (τ = +1): convert only because you intervened. The entire ROI of any campaign lives here.
- Sure things (τ = 0): convert regardless. Treating them spends budget to buy nothing — and these are precisely the users a conversion model ranks at the top.
- Lost causes (τ = 0): never convert either way. Harmless but wasted spend.
- Sleeping dogs (τ = −1): treatment backfires — the unnecessary push annoys them into unsubscribing or churning. Targeting them is actively negative-value.
The punchline: ranking by predicted P(convert) systematically targets the sure things and ignores the persuadables. A user with 90% baseline conversion has almost no headroom — treating them can only move them a few points. A user at 30% baseline who jumps to 70% under treatment has a +40-point uplift and is invisible to a conversion ranker. Uplift modeling reorders your targeting around τ(x), not P(Y=1 | x). The interactive below makes the budget consequences concrete.
CATE estimators — the meta-learners
Given randomized (or unconfounded) data with features X, treatment T, outcome Y, how do you estimate τ(x)? The meta-learners are recipes that wrap any off-the-shelf regressor (a "base learner") into a CATE estimator. Three you must know:
| Learner | Recipe | Trade-off |
|---|---|---|
| S-learner (single) | Train one model μ(x, t) on all data with treatment t as just another feature. Estimate τ̂(x) = μ(x,1) − μ(x,0). | Lowest variance, simplest. But if the learner regularizes t away (one feature among hundreds), it predicts τ ≈ 0 everywhere — biased toward no effect. Dangerous when the true uplift is small. |
| T-learner (two) | Train two separate models: μ_1(x) on the treated, μ_0(x) on the control. τ̂(x) = μ_1(x) − μ_0(x). | Cannot regularize the effect away — treatment cannot be ignored because it defines the split. But each model sees half the data, and the two error surfaces don't cancel → higher variance, especially when groups are imbalanced. |
| X-learner (cross) | Fit T-learner models, then impute each unit's individual effect using the other group's model and regress on those imputed effects, weighting by the propensity e(x). | Best of both when treatment groups are very imbalanced (e.g. few treated): borrows strength from the large group to estimate effects in the small one. More moving parts, more to tune. |
The X-learner recipe in full, because interviewers ask for it: (1) fit μ_0, μ_1 as in the T-learner. (2) Impute the treated units' effects as D_1 = Y - μ_0(X) and the control units' as D_0 = μ_1(X) - Y. (3) Regress D_1 on X to get τ_1(x), and D_0 on X to get τ_0(x). (4) Combine with the propensity as a weight: τ̂(x) = e(x) τ_0(x) + (1 − e(x)) τ_1(x). When treated units are rare, e(x) is small, so the estimate leans on τ_1 — the effects imputed for the many control units — which is exactly the strength-borrowing you want.
Causal forests — honesty
A causal forest is a random forest whose splits maximize treatment-effect heterogeneity rather than outcome purity — each split tries to separate high-uplift from low-uplift users. Its key trick is honest splitting: one subsample decides the tree structure (where to split), a disjoint subsample estimates the effect inside each leaf. Reusing the same data for both would let the tree overfit splits to noise and then "confirm" that noise in the leaf estimate. Honesty buys valid confidence intervals on τ(x) — rare and precious in CATE estimation, since you can never check against a ground-truth ITE.
Evaluating uplift — Qini and AUUC
The fix: don't grade per-user, grade the ranking. Sort the population by predicted uplift descending. Walk down the list; at each depth, compute the actual outcome gap between treated and control units among those targeted so far. A good uplift model puts the persuadables first, so the cumulative gain rises steeply early and the curve bows above the random-targeting diagonal.
- Uplift curve: cumulative incremental conversions vs fraction of population targeted.
- Qini curve: the same idea, normalized for treated/control group-size imbalance (the Qini coefficient is the area between your curve and the random line).
- AUUC (Area Under the Uplift Curve): a single scalar summary, the uplift analogue of AUC. Higher = your ranking concentrates true incremental effect at the top.
A flat or below-diagonal Qini curve means your "uplift" model is no better than random targeting — or worse, is sorting sure things to the top.
Observational causal methods — when there is no experiment
No randomization means treatment is confounded: the users who got treated differ systematically from those who didn't, in ways that also drive the outcome. Every method below is a different strategy for breaking that confounding, and each rests on one load-bearing assumption that, if false, silently invalidates the whole estimate. Know the assumption better than the method.
Two assumptions underlie the entire observational program and deserve naming up front:
- Unconfoundedness / ignorability: (Y(0), Y(1)) ⊥ T | X — conditional on observed features, treatment is as-good-as-random. This is the big, untestable one: it fails the moment an unobserved variable drives both treatment and outcome.
- Overlap / positivity: 0 < e(x) < 1 for all x — every kind of user had some chance of being treated and some chance of not. No overlap → you are extrapolating into regions with no comparison units.
- SUTVA: one unit's treatment doesn't affect another's outcome (no interference), and there is one well-defined version of the treatment. Network effects and spillovers in social/ads settings violate this constantly.
| Method | Idea | The one assumption that sinks it if violated |
|---|---|---|
| Propensity-score matching (PSM) | Estimate e(x) = P(T=1 | x), then pair each treated unit with a control unit of nearly equal propensity and compare. Collapses high-dim matching to a 1-D score. | Unconfoundedness — you can only match on observed covariates. A hidden confounder you didn't put in e(x) leaves the matched pairs still unbalanced, and no amount of matching fixes it. |
| Inverse propensity weighting (IPW) | Reweight each unit by 1/e(x) (treated) or 1/(1-e(x)) (control) to synthesize a pseudo-population in which treatment is independent of X. Same propensity machinery as lesson 07 · Bias & debiasing — there it debiases logged clicks for ranking; here it debiases treatment groups for an effect estimate. | Overlap — a unit with e(x) → 0 gets weight → ∞, so a handful of near-deterministic units explode the variance (exactly the IPS variance blow-up from lesson 07; doubly-robust estimators are the shared fix). |
| Difference-in-differences (DID) | A group gets treated at time t, another doesn't. Compare the treated group's change (after − before) to the control group's change — differencing out any fixed group gap and any common time trend. | Parallel trends — absent treatment, both groups would have moved in parallel. Untestable for the post period; if the treated group was already on a different trajectory, you attribute that divergence to the treatment. |
| Synthetic control | When you have one treated unit (one market, one region), build a weighted blend of untreated units that tracks the treated unit's pre-period series, then read the gap post-treatment as the effect. | Good pre-period fit from a convex donor pool — the synthetic must match the treated unit before treatment using only untreated donors. Poor pre-fit, or no donor combination that reproduces the treated trajectory, and the post-period gap is meaningless. |
| Instrumental variables (IV) | Find an instrument Z that shifts treatment but affects the outcome only through treatment. Use the Z-induced variation in T as quasi-random (two-stage least squares). | Exclusion restriction — Z must have no direct path to Y except via T. Untestable, and almost any plausible instrument has some back-channel to the outcome, which biases the estimate. |
The DID estimator is worth seeing as a clean 2×2, because it is the one observational design you can sketch on a whiteboard in ten seconds:
τ̂_DID = (Ȳ_(treat,after) − Ȳ_(treat,before)) − (Ȳ_(ctrl,after) − Ȳ_(ctrl,before)).
| before | after | change | |
|---|---|---|---|
| treated group | 10 | 18 | +8 |
| control group | 12 | 15 | +3 |
| DID effect | +8 − 3 = +5 |
The control group's +3 is the "what would have happened anyway" trend; subtracting it leaves +5 as the treatment's incremental effect — if parallel trends holds. Note the IPW estimator is the same inverse-propensity weight you met in lesson 07, just summed into an effect rather than a loss:
τ̂_IPW = (1/n) Σ_i [ (T_i Y_i)/(e(x_i)) − ((1 − T_i) Y_i)/(1 − e(x_i)) ].
The recsys / ads application
This is where uplift earns its keep — every interruptive intervention has a cost and a backfire mode:
- Notifications & push. The sure things open the app anyway; pushing them wastes a notification slot. The sleeping dogs are the dangerous quadrant — an unwanted 2 a.m. push is how you train a user to disable notifications or uninstall. Target persuadable opens, and explicitly model the sleeping-dog churn risk as negative uplift.
- Ads & coupons. A coupon to a sure-thing buyer is pure margin given away. Uplift modeling redirects the discount budget to the persuadables — the users whose purchase decision actually flips on the discount — which is the difference between a coupon program that prints money and one that subsidizes existing demand.
- Feed re-ranking. Re-ranking away from the default has a cost (lower immediate engagement) and a possible long-run benefit (diversity, retention). That is an uplift question on a slow outcome — often the case where you cannot A/B cheaply and reach for DID or a geo-based synthetic control.
- Budget & pacing. Incremental-value targeting plugs straight into the bidding logic of lesson 10 · Bidding & pacing: bid (or spend) in proportion to incremental conversion value τ(x) · v, not predicted conversion value, so the pacer stops overpaying to reach users who'd have converted for free.
Interactive · uplift targeting vs the naive ranker
A population of 10,000 users splits into the four response types in tunable proportions. Each treatment costs money; each incremental conversion is worth something. Compare two targeting strategies at a chosen budget: target by predicted P(convert) (the naive conversion ranker — it loves sure things) versus target by predicted uplift (persuadables first). Watch net profit, wasted spend on sure things, and annoyed sleeping dogs diverge.
Interview prompts you should be ready for
- "What's the difference between a model that predicts conversion and one that estimates uplift, and why does it matter for a coupon budget?" (Prediction estimates E[Y | X, treated]; uplift estimates E[Y(1) − Y(0) | X]. Ranking by predicted conversion targets sure things — users who'd convert anyway — so the coupon buys nothing. Uplift targets persuadables, the only quadrant with positive ROI. Name the four-quadrant picture.)
- "State the fundamental problem of causal inference and how randomization gets around it." (You observe at most one of Y(1), Y(0) per unit, so the individual effect is never seen. Randomization makes T independent of all confounders, so the difference of treated and control group means is unbiased for the ATE — you recover an average over the unobservable counterfactuals.)
- "Compare S-, T-, and X-learners." (S: one model with treatment as a feature — low variance but can regularize the effect to ~0. T: separate treated/control models — can't ignore treatment but higher variance, each sees half the data. X: impute individual effects via the other group's model and reweight by propensity — best when treatment groups are very imbalanced, at the cost of complexity.)
- "You can't run an A/B test because the feature already shipped to everyone. How do you estimate its causal effect?" (No control group, so reach for a quasi-experiment: difference-in-differences against an untreated segment/geo (needs parallel trends), or synthetic control if there's a single treated unit and a good donor pool. State the load-bearing assumption and how you'd probe it — e.g., a pre-period placebo test for parallel trends.)
- "How do you evaluate an uplift model offline, and why can't you use AUC?" (The true ITE is never observed, so there's no per-user label for accuracy/AUC. Use the uplift/Qini curve: sort by predicted uplift, plot cumulative treated-minus-control gain vs fraction targeted; AUUC summarizes it. A below-diagonal curve means you're no better than random — or are sorting sure things to the top.)
- "PSM and IPW both use the propensity score — how do they differ, and which assumption is fatal to each?" (PSM matches treated to control units of equal propensity; IPW reweights by 1/e(x) to synthesize a balanced pseudo-population. PSM is sunk by unconfoundedness — you can only match on observed covariates. IPW is sunk by overlap — e(x)→0 sends weights to infinity and variance explodes. Same propensity as lesson 07's IPS; doubly-robust is the shared variance fix.)
- "When would you choose a bandit over an uplift model over plain RL?" (Bandit when you can randomize online and want to learn effects while bounding regret — it's a continuous built-in experiment. Observational uplift when you're stuck with a fixed log and can't randomize. RL when the intervention's effect compounds over a sequence and you're optimizing long-run reward, not a one-shot outcome. All three pick actions by causal effect, not passive prediction.)