Type at least 2 letters. Enter opens the first result, Esc closes.

    Causal Inference · Lesson 8 · Causal ML, counterfactuals and discovery

    Heterogeneous effects and causal ML: meta-learners, double ML and causal forests

    Advanced 110 min 5 interactive figures 8 videos Colab notebook

    Before this lesson: potential outcomes and the CATE (lesson 02); conditional exchangeability, positivity, the propensity score and AIPW (lesson 05); regularization (ridge and lasso), cross-validation, decision trees, random forests and boosting (standard supervised learning); projections (linear algebra 03) help for section 3.3. Time: about 110 minutes, plus the notebook. This is the heaviest lesson of the track. The two folded deeper blocks can be skipped on a first reading.


    Why this matters #

    Many decisions are about whom to treat, not whether to treat: which users get a discount, which patients get a drug with side effects, which job seekers get a training program. A model that predicts "who will buy" or "who will churn" answers the wrong question. The right question is "for whom does the treatment change the outcome?". This is uplift modeling in marketing and personalised medicine in health. Tech companies look for effects that differ between user groups in every large A/B test.

    The second use is estimating one effect with many covariates. With 100 confounders, a linear regression can be badly misspecified, and a plain ML model gives biased effects (section 3.3). Double/debiased machine learning (Chernozhukov et al. 2018) is now a standard tool in economics, epidemiology and industry: it gives a n\sqrt n-consistent estimate and a valid confidence interval while gradient boosting or random forests model the confounding. The ideas of this lesson (orthogonal scores, cross-fitting, honest estimation) also appear in off-policy evaluation (lesson 11) and in modern semiparametric statistics.

    1. Predict first #

    2. The picture #

    2.1 The effect is a gap between two curves #

    Take one covariate xx. The outcome regressions are μ0(x)=E[Y∣T=0,X=x]\mu_0(x) = \mathbb{E}[Y \mid T = 0, X = x] (the average outcome of controls with features xx) and μ1(x)=E[Y∣T=1,X=x]\mu_1(x) = \mathbb{E}[Y \mid T = 1, X = x]. Under the assumptions of lesson 05, the CATE is the vertical gap between the two curves:

    τ(x)=E[Y(1)−Y(0)∣X=x]=μ1(x)−μ0(x).\tau(x) = \mathbb{E}[Y(1) - Y(0) \mid X = x] = \mu_1(x) - \mu_0(x).

    Why is this hard, even with good ML models? Three reasons.

    • The gap is small and simple; the curves are big and complex. In the figure below, the baseline μ0(x)\mu_0(x) goes up and down by about 4 units, while the effect changes slowly between 0.5s0.5s and 1.5s1.5s. A model that predicts YY well spends its effort on the big wiggles, not on the small gap.
    • Errors do not cancel. τ^=μ^1−μ^0\hat\tau = \hat\mu_1 - \hat\mu_0 carries the error of both models. If μ^1\hat\mu_1 is fitted on few points, its error is large, and all of it lands in τ^\hat\tau.
    • Regularization works against the gap. Regularization pulls a model toward simple functions. If TT is one input among many, "simple" can mean "ignore TT", which sets τ^\hat\tau to 0.

    A meta-learner is a recipe that turns any regression method (a forest, boosting, a neural network, a kernel smoother) into a CATE estimator. Four common recipes, in words:

    • S-learner ("single"): fit one model μ^(x,t)\hat\mu(x, t) with TT as an extra input; then τ^(x)=μ^(x,1)−μ^(x,0)\hat\tau(x) = \hat\mu(x, 1) - \hat\mu(x, 0).
    • T-learner ("two"): fit μ^1\hat\mu_1 on the treated and μ^0\hat\mu_0 on the controls; subtract.
    • X-learner: first a T-learner. Then impute an effect for every unit with the other group's model, fit a model to these effects, and mix the two effect models.
    • DR-learner: build a "doubly robust" pseudo-outcome for every unit (the AIPW term of lesson 05) and regress it on xx.
    Interactive figure: loading…

    Start with the T-learner at 10% treated. Treated and control points come from the same wiggly baseline; the true effect τ(x)\tau(x) is smooth. The fitted models are drawn in the group colors, and the black curve is the estimate τ^(x)\hat\tau(x). Notice the false wiggles: the treated model is too smooth to follow the baseline. Switch to X: the wiggles disappear, because the X-learner fits a smooth model to imputed effects. Now pick S and raise the effect size to 3: the estimate is pulled toward 0. Pick DR at 10% treated, then at 50%: the DR-learner is noisy where the propensity is near 0 and good with balanced groups. The readout compares the ATE from τ^\hat\tau with the true ATE and the naive difference in means, which is confounded here because treatment is more likely for large xx.

    The figure shows the main trade-offs. No learner wins everywhere; section 3.2 gives a table.

    Quick check

    A gradient-boosting model with strong regularization predicts YY from (X,T)(X, T). The true effect of TT is real but small compared with how much YY varies with XX. What do you expect for τ^(x)=f^(x,1)−f^(x,0)\hat\tau(x) = \hat f(x, 1) - \hat f(x, 0)?

    2.2 Partialling out: residual on residual #

    Now take a different question: one number θ\theta, the effect of TT on YY, when many covariates XX confound it. Linear regression of YY on TT and XX answers it only if the confounding is linear. The Frisch–Waugh–Lovell (FWL) theorem shows another way to compute the coefficient of TT:

    1. Predict TT from XX and keep the residual T~=T−m^(X)\tilde T = T - \hat m(X): the part of the treatment that XX does not explain.
    2. Predict YY from XX and keep the residual Y~=Y−ℓ^(X)\tilde Y = Y - \hat \ell(X).
    3. Regress Y~\tilde Y on T~\tilde T. The slope is the effect.

    With linear predictions in steps 1 and 2, the slope is exactly the multiple-regression coefficient. Double machine learning replaces the linear predictions by ML models. That is the whole idea.

    Interactive figure: loading…

    Step through the four panels. In panel 0 the naive slope of YY on TT is about 1.3, far from the true θ=0.5\theta = 0.5 (dashed). Panels 1 and 2 fit TT and YY on XX (black curve). In panel 3, the slope of the residuals with a linear fit is about 1.1: it equals the coefficient of TT in Y∼1+T+XY \sim 1 + T + X to all digits (FWL), but it is still biased, because the confounding is curved. Switch to flexible: the residuals lose the curved confounding too, and the slope is close to 0.5.

    Quick check

    In the T-learner panel of the first figure, only 10% of units are treated, the baseline μ0\mu_0 is wiggly and the effect τ\tau is smooth. Which change helps most?

    3. Definitions and main results #

    3.1 The CATE and its identification #

    Definition. The conditional average treatment effect (CATE) is τ(x)=E[Y(1)−Y(0)∣X=x]\tau(x) = \mathbb{E}[Y(1) - Y(0) \mid X = x]. The ATE is its average: τATE=E[τ(X)]\tau_{\mathrm{ATE}} = \mathbb{E}[\tau(X)].

    The CATE is not the individual effect τi=Yi(1)−Yi(0)\tau_i = Y_i(1) - Y_i(0). Two people with the same xx can react differently; τ(x)\tau(x) is their average. With richer xx, τ(x)\tau(x) gets closer to individual effects, but it never becomes them.

    Assumptions (lesson 05, now used for every xx):

    1. Consistency: Y=Y(T)Y = Y(T).
    2. Conditional exchangeability: (Y(0),Y(1))⊥ ⁣ ⁣ ⁣⊥T∣X(Y(0), Y(1)) \perp\!\!\!\perp T \mid X (no unmeasured confounding).
    3. Positivity (overlap): 0<e(x)<10 < e(x) < 1 for every xx we want to evaluate.

    Theorem (identification of the CATE). Under 1–3, τ(x)=μ1(x)−μ0(x)\tau(x) = \mu_1(x) - \mu_0(x).

    Proof (for μ1\mu_1; μ0\mu_0 is the same).

    1. Positivity gives P(T=1∣X=x)>0P(T = 1 \mid X = x) > 0, so μ1(x)=E[Y∣T=1,X=x]\mu_1(x) = \mathbb{E}[Y \mid T = 1, X = x] is defined.
    2. Consistency: E[Y∣T=1,X=x]=E[Y(1)∣T=1,X=x]\mathbb{E}[Y \mid T = 1, X = x] = \mathbb{E}[Y(1) \mid T = 1, X = x].
    3. Exchangeability: E[Y(1)∣T=1,X=x]=E[Y(1)∣X=x]\mathbb{E}[Y(1) \mid T = 1, X = x] = \mathbb{E}[Y(1) \mid X = x].
    4. Subtract the same chain for t=0t = 0. ■\blacksquare

    Positivity can be checked (look at e^(x)\hat e(x)). Exchangeability cannot: machine learning does not remove a confounder that is not in XX. Everything below is about estimation: the estimand is fixed by the theorem, and the methods differ in how well they estimate it.

    3.2 Meta-learners #

    Let A\mathcal{A} be any regression method ("fit ZZ on WW"). The four learners of section 2, written out:

    Learner Recipe Good when Weak when
    S fit μ^(x,t)\hat\mu(x, t) on all data; τ^(x)=μ^(x,1)−μ^(x,0)\hat\tau(x) = \hat\mu(x, 1) - \hat\mu(x, 0) effect zero or small; little data real effect, strong regularization: τ^\hat\tau shrinks to 0
    T fit μ^1\hat\mu_1 on treated, μ^0\hat\mu_0 on controls; subtract much data in both groups; μ1,μ0\mu_1, \mu_0 very different one group small; τ\tau simpler than μt\mu_t
    X T-learner, then impute effects, fit τ^1,τ^0\hat\tau_1, \hat\tau_0, mix with e^\hat e unbalanced groups; smooth τ\tau both groups small; poor e^\hat e
    DR regress the AIPW pseudo-outcome on xx (cross-fitted) good overlap; want robustness e^(x)\hat e(x) near 0 or 1: huge pseudo-outcomes

    X-learner (Künzel, Sekhon, Bickel and Yu 2019), step by step:

    1. Fit μ^0\hat\mu_0 on the controls and μ^1\hat\mu_1 on the treated.
    2. Impute individual effects. For a treated unit, Di1=Yi−μ^0(Xi)D_i^1 = Y_i - \hat\mu_0(X_i) (observed outcome minus the predicted outcome without treatment). For a control unit, Di0=μ^1(Xi)−YiD_i^0 = \hat\mu_1(X_i) - Y_i.
    3. Fit τ^1\hat\tau_1 on the treated with target D1D^1, and τ^0\hat\tau_0 on the controls with target D0D^0.
    4. Mix: τ^(x)=g(x) τ^0(x)+(1−g(x)) τ^1(x)\hat\tau(x) = g(x)\,\hat\tau_0(x) + (1 - g(x))\,\hat\tau_1(x) with g(x)=e^(x)g(x) = \hat e(x).

    Why this weight? With few treated units (e^\hat e small), τ^1\hat\tau_1 is the better model: it uses the control model μ^0\hat\mu_0, fitted on many points, and its target D1D^1 is the smooth effect plus noise. So the weight 1−e^(x)1 - \hat e(x) on τ^1\hat\tau_1 is large. With few controls, the roles swap.

    DR-learner (Kennedy 2023). Split the data. On one part, fit μ^0,μ^1,e^\hat\mu_0, \hat\mu_1, \hat e. On the other part, compute for each unit the pseudo-outcome

    φ^i=μ^1(Xi)−μ^0(Xi)+Ti (Yi−μ^1(Xi))e^(Xi)−(1−Ti) (Yi−μ^0(Xi))1−e^(Xi),\hat\varphi_i = \hat\mu_1(X_i) - \hat\mu_0(X_i) + \frac{T_i\,(Y_i - \hat\mu_1(X_i))}{\hat e(X_i)} - \frac{(1 - T_i)\,(Y_i - \hat\mu_0(X_i))}{1 - \hat e(X_i)},

    and regress φ^\hat\varphi on XX. Swap the parts and average. Its average over all units is the AIPW estimate of the ATE from lesson 05.

    Theorem (the pseudo-outcome is doubly robust). Let μˉt,eˉ\bar\mu_t, \bar e be fixed functions (the fitted models, from the other part of the data). Under assumptions 1–3,

    E[φ∣X=x]−τ(x)=(e(x)−eˉ(x))[μ1(x)−μˉ1(x)eˉ(x)+μ0(x)−μˉ0(x)1−eˉ(x)].\mathbb{E}[\varphi \mid X = x] - \tau(x) = \big(e(x) - \bar e(x)\big)\left[\frac{\mu_1(x) - \bar\mu_1(x)}{\bar e(x)} + \frac{\mu_0(x) - \bar\mu_0(x)}{1 - \bar e(x)}\right].

    So the target of the regression is exactly τ(x)\tau(x) if eˉ=e\bar e = e, or if both μˉt=μt\bar\mu_t = \mu_t.

    Proof
    1. Given X=xX = x: E[TY∣X=x]=e(x) μ1(x)\mathbb{E}[T Y \mid X = x] = e(x)\,\mu_1(x) and E[T∣X=x]=e(x)\mathbb{E}[T \mid X = x] = e(x). So E[T(Y−μˉ1(X))/eˉ(X)∣X=x]=e(x)eˉ(x)(μ1(x)−μˉ1(x))\mathbb{E}\big[T(Y - \bar\mu_1(X))/\bar e(X) \mid X = x\big] = \frac{e(x)}{\bar e(x)}\big(\mu_1(x) - \bar\mu_1(x)\big).
    2. In the same way, E[(1−T)(Y−μˉ0(X))/(1−eˉ(X))∣X=x]=1−e(x)1−eˉ(x)(μ0(x)−μˉ0(x))\mathbb{E}\big[(1 - T)(Y - \bar\mu_0(X))/(1 - \bar e(X)) \mid X = x\big] = \frac{1 - e(x)}{1 - \bar e(x)}\big(\mu_0(x) - \bar\mu_0(x)\big).
    3. Add μˉ1−μˉ0\bar\mu_1 - \bar\mu_0 and write μˉ1+eeˉ(μ1−μˉ1)=μ1+(μ1−μˉ1)e−eˉeˉ\bar\mu_1 + \frac{e}{\bar e}(\mu_1 - \bar\mu_1) = \mu_1 + (\mu_1 - \bar\mu_1)\frac{e - \bar e}{\bar e}. For the control part, μˉ0+1−e1−eˉ(μ0−μˉ0)=μ0−(μ0−μˉ0)e−eˉ1−eˉ\bar\mu_0 + \frac{1 - e}{1 - \bar e}(\mu_0 - \bar\mu_0) = \mu_0 - (\mu_0 - \bar\mu_0)\frac{e - \bar e}{1 - \bar e}.
    4. Subtract: E[φ∣X=x]=μ1−μ0+(e−eˉ)[μ1−μˉ1eˉ+μ0−μˉ01−eˉ]\mathbb{E}[\varphi \mid X = x] = \mu_1 - \mu_0 + (e - \bar e)\big[\frac{\mu_1 - \bar\mu_1}{\bar e} + \frac{\mu_0 - \bar\mu_0}{1 - \bar e}\big], and μ1−μ0=τ(x)\mu_1 - \mu_0 = \tau(x) by section 3.1. ■\blacksquare

    The error is a product of a propensity error and an outcome-model error. Kennedy (2023) shows that, because of this, the DR-learner can reach the error rate of an "oracle" that regresses the true φ\varphi on XX, even when the nuisance models converge more slowly. The same product structure is the key to double ML in the next section.

    3.3 Double machine learning for one effect #

    The model. The partially linear model (Robinson 1988) is

    Y=θ T+g(X)+ε,E[ε∣X,T]=0;T=m(X)+v,E[v∣X]=0.Y = \theta\,T + g(X) + \varepsilon, \quad \mathbb{E}[\varepsilon \mid X, T] = 0; \qquad T = m(X) + v, \quad \mathbb{E}[v \mid X] = 0.

    gg and mm can be any functions (they carry the confounding). The effect of TT is the same number θ\theta for everybody. TT can be binary or continuous (a dose, a price). Under conditional exchangeability, θ\theta is the causal effect.

    Step 1: Frisch–Waugh–Lovell. Take expectations given XX: ℓ(X)=E[Y∣X]=θ m(X)+g(X)\ell(X) = \mathbb{E}[Y \mid X] = \theta\,m(X) + g(X). Subtract this from YY:

    Y−ℓ(X)=θ (T−m(X))+ε.Y - \ell(X) = \theta\,\big(T - m(X)\big) + \varepsilon .

    This is Robinson's transformation: the residual of YY is θ\theta times the residual of TT, plus noise. So θ\theta is the slope of a regression through the origin: θ=E[T~Y~]/E[T~2]\theta = \mathbb{E}[\tilde T \tilde Y] / \mathbb{E}[\tilde T^2], with T~=T−m(X)\tilde T = T - m(X) and Y~=Y−ℓ(X)\tilde Y = Y - \ell(X). When mm and ℓ\ell are linear projections, this is the FWL theorem.

    FWL theorem for linear regression

    Let WW be the n×pn \times p matrix of covariates (with a column of ones), P=W(W⊤W)−1W⊤P = W(W^\top W)^{-1}W^\top the projection onto its column space (linear algebra 03), and M=I−PM = I - P. OLS of YY on (T,W)(T, W) gives Y=β^T+Wγ^+rY = \hat\beta T + W\hat\gamma + r, with a residual rr orthogonal to TT and to every column of WW.

    1. Multiply by MM: MW=0MW = 0, and Mr=rMr = r (because Pr=0Pr = 0). So MY=β^ MT+rMY = \hat\beta\,MT + r.
    2. Multiply by (MT)⊤(MT)^\top: (MT)⊤MY=β^ (MT)⊤MT+T⊤Mr(MT)^\top MY = \hat\beta\,(MT)^\top MT + T^\top M r.
    3. T⊤Mr=T⊤r−T⊤Pr=0−0T^\top M r = T^\top r - T^\top P r = 0 - 0. So β^=(MT)⊤(MY)(MT)⊤(MT)\hat\beta = \dfrac{(MT)^\top (MY)}{(MT)^\top (MT)}.
    4. MT=T~MT = \tilde T and MY=Y~MY = \tilde Y are the residuals of TT and YY on WW. So β^\hat\beta is the slope of Y~\tilde Y on T~\tilde T. ■\blacksquare

    Step 2: replace the projections by ML models. Fit m^(X)≈E[T∣X]\hat m(X) \approx \mathbb{E}[T \mid X] and ℓ^(X)≈E[Y∣X]\hat\ell(X) \approx \mathbb{E}[Y \mid X] with any ML method. Both are ordinary prediction problems, so they can be tuned by cross-validation.

    Step 3: the DML estimator with cross-fitting (Chernozhukov et al. 2018):

    1. Split the nn units at random into KK folds (often K=5K = 5).
    2. For each fold kk: fit ℓ^(−k)\hat\ell^{(-k)} and m^(−k)\hat m^{(-k)} on the other folds, and compute the residuals of the units in fold kk: Y~i=Yi−ℓ^(−k)(Xi)\tilde Y_i = Y_i - \hat\ell^{(-k)}(X_i), T~i=Ti−m^(−k)(Xi)\tilde T_i = T_i - \hat m^{(-k)}(X_i).
    3. Pool all units:
    θ^=∑i=1nT~i Y~i∑i=1nT~i2,SE^=∑iT~i2 (Y~i−θ^ T~i)2∑iT~i2.\hat\theta = \frac{\sum_{i=1}^n \tilde T_i\,\tilde Y_i}{\sum_{i=1}^n \tilde T_i^2}, \qquad \widehat{\mathrm{SE}} = \frac{\sqrt{\sum_i \tilde T_i^2\,(\tilde Y_i - \hat\theta\,\tilde T_i)^2}}{\sum_i \tilde T_i^2}.
    1. The 95% confidence interval is θ^±1.96 SE^\hat\theta \pm 1.96\,\widehat{\mathrm{SE}}. In practice, repeat with several random splits and report the median.

    Why not just plug in an ML model? A natural "plug-in" estimator fits g^\hat g with ML and then regresses Y−g^(X)Y - \hat g(X) on TT. Its error contains the term 1n∑iTi (g−g^)(Xi)≈E[m(X) (g−g^)(X)]\frac{1}{n}\sum_i T_i\,(g - \hat g)(X_i) \approx \mathbb{E}[m(X)\,(g - \hat g)(X)]: the error of g^\hat g enters directly (first order), multiplied by the confounding m(X)m(X). ML models are regularized, so g^−g\hat g - g shrinks more slowly than 1/n1/\sqrt n, and this regularization bias dominates the statistical noise. The confidence interval then misses θ\theta.

    Why DML is different: errors multiply. Write the nuisance errors as Δm=m^−m\Delta_m = \hat m - m and Δℓ=ℓ^−ℓ\Delta_\ell = \hat\ell - \ell. Then T~=v−Δm\tilde T = v - \Delta_m and, from Robinson's transformation, Y~−θT~=ε−Δℓ+θ Δm\tilde Y - \theta\tilde T = \varepsilon - \Delta_\ell + \theta\,\Delta_m. So

    θ^−θ=1n∑iT~i(Y~i−θT~i)1n∑iT~i2,T~(Y~−θT~)=v ε⏟noise  − v Δℓ+θ v Δm−ε Δm⏟noise × error  +  Δm (Δℓ−θ Δm)⏟error × error.\hat\theta - \theta = \frac{\frac1n\sum_i \tilde T_i(\tilde Y_i - \theta\tilde T_i)}{\frac1n\sum_i \tilde T_i^2}, \qquad \tilde T(\tilde Y - \theta \tilde T) = \underbrace{v\,\varepsilon}_{\text{noise}} \;\underbrace{-\, v\,\Delta_\ell + \theta\,v\,\Delta_m - \varepsilon\,\Delta_m}_{\text{noise}\,\times\,\text{error}} \;+\; \underbrace{\Delta_m\,(\Delta_\ell - \theta\,\Delta_m)}_{\text{error}\,\times\,\text{error}} .
    • The first term gives the normal distribution of θ^\hat\theta, with standard error of order 1/n1/\sqrt n.
    • The middle terms have mean zero if the nuisance models were fitted on other data, because E[v∣X]=0\mathbb{E}[v \mid X] = 0 and E[ε∣X]=0\mathbb{E}[\varepsilon \mid X] = 0. This is what cross-fitting buys.
    • The last term is the only bias, and it is a product of two errors. If each error is about 10%10\%, the bias is about 1%1\%.
    Interactive figure: loading…

    Two views of why DML works. 200 simulations: each run draws a data set from a partially linear model with θ=0.5\theta = 0.5 and computes three estimates, with kk-nearest-neighbor regression as the ML model. At k=2k = 2 the outcome model nearly memorises each point: the grey histogram (DML without cross-fitting) shrinks toward 0, but cross-fitting (black) stays centered. Move the slider to k=80k = 80 or 150150: the outcome model is now too smooth, and the plug-in estimate moves away from 0.5, while DML stays close. The readout also shows how often the 95% CI covers θ\theta. Errors multiply: exact formulas for a model where both nuisance models are off by δ\delta; the plug-in bias grows like δ/2\delta/2, the DML bias like δ2/2\delta^2/2. Simulated in your browser with the model described in the notes of section 3.3.

    Neyman orthogonality. The DML estimator solves the moment equation 1n∑iψ(Wi;θ^,η^)=0\frac1n \sum_i \psi(W_i; \hat\theta, \hat\eta) = 0 with the score ψ(W;θ,η)=(Y−ℓ(X)−θ(T−m(X)))(T−m(X))\psi(W; \theta, \eta) = \big(Y - \ell(X) - \theta(T - m(X))\big)\big(T - m(X)\big) and nuisance η=(ℓ,m)\eta = (\ell, m). A score is Neyman orthogonal if, at the true values,

    ∂∂r E[ψ(W;θ0,η0+r (η−η0))]∣r=0=0for every direction η−η0.\frac{\partial}{\partial r}\, \mathbb{E}\big[\psi(W; \theta_0, \eta_0 + r\,(\eta - \eta_0))\big]\Big|_{r = 0} = 0 \quad \text{for every direction } \eta - \eta_0 .

    In words: a small change in the nuisance functions does not change the moment condition to first order.

    Proof that the DML score is orthogonal. Take a direction (δℓ,δm)(\delta_\ell, \delta_m), functions of XX.

    1. Differentiate inside the expectation at r=0r = 0: E[(−δℓ+θ0 δm)(X) (T−m(X))]+E[(Y−ℓ(X)−θ0(T−m(X))) (−δm(X))]\mathbb{E}\big[(-\delta_\ell + \theta_0\,\delta_m)(X)\,(T - m(X))\big] + \mathbb{E}\big[(Y - \ell(X) - \theta_0(T - m(X)))\,(-\delta_m(X))\big].
    2. First term: condition on XX; E[T−m(X)∣X]=E[v∣X]=0\mathbb{E}[T - m(X) \mid X] = \mathbb{E}[v \mid X] = 0. So it is 0.
    3. Second term: Y−ℓ−θ0(T−m)=εY - \ell - \theta_0(T - m) = \varepsilon by Robinson's transformation, and E[ε δm(X)]=E[δm(X) E[ε∣X]]=0\mathbb{E}[\varepsilon\,\delta_m(X)] = \mathbb{E}\big[\delta_m(X)\,\mathbb{E}[\varepsilon \mid X]\big] = 0. ■\blacksquare

    The plug-in score ψ=(Y−θT−g(X)) T\psi = (Y - \theta T - g(X))\,T is not orthogonal: its derivative in the direction δg\delta_g is −E[δg(X) T]=−E[δg(X) m(X)]-\mathbb{E}[\delta_g(X)\,T] = -\mathbb{E}[\delta_g(X)\,m(X)], which is not 0 when TT is confounded. This is the regularization bias above.

    Cross-fitting. If ℓ^\hat\ell was fitted on unit ii itself, it has partly learned unit ii's noise θvi+εi\theta v_i + \varepsilon_i. Then Δℓ(Xi)\Delta_\ell(X_i) is correlated with viv_i, the middle term −vi Δℓ(Xi)-v_i\,\Delta_\ell(X_i) no longer has mean zero, and θ^\hat\theta is biased (toward 0 in the figure). Fitting the nuisances on other folds removes this dependence. Cross-fitting does not waste data: every unit is used for the final estimate, and every unit helps fit the nuisance models of the other folds. (This is the same idea as cross-validation: never evaluate a model on the points it was trained on.)

    Theorem (DML, informal; Chernozhukov et al. 2018, Theorem 4.1). In the partially linear model, assume E[v2]>0\mathbb{E}[v^2] > 0, bounded moments, cross-fitting, and nuisance errors (in mean square) that satisfy

    ∥m^−m∥2⋅(∥m^−m∥2+∥ℓ^−ℓ∥2)=oP(n−1/2).\|\hat m - m\|_2 \cdot \big(\|\hat m - m\|_2 + \|\hat\ell - \ell\|_2\big) = o_P(n^{-1/2}).

    Then n (θ^−θ)→N(0,σ2)\sqrt n\,(\hat\theta - \theta) \to \mathcal N(0, \sigma^2) with σ2=E[v2ε2]/(E[v2])2\sigma^2 = \mathbb{E}[v^2\varepsilon^2] / (\mathbb{E}[v^2])^2, and the interval of step 4 has coverage 95%95\% in large samples.

    The rate condition holds, for example, if each nuisance error is o(n−1/4)o(n^{-1/4}): much slower than the n−1/2n^{-1/2} of the final estimate. Random forests, boosting and lasso reach such rates under suitable conditions. This is the precise meaning of "two slow errors give one fast estimate".

    Quick check

    In the FWL theorem, the coefficient of TT in the OLS regression of YY on (1,T,X)(1, T, X) equals the slope of which regression?

    Quick check

    You compute DML residuals with nuisance models that were trained on all nn units, including the unit being predicted. What goes wrong?

    3.4 AIPW is double ML for the ATE #

    For a binary TT and heterogeneous effects, the target τATE=E[μ1(X)−μ0(X)]\tau_{\mathrm{ATE}} = \mathbb{E}[\mu_1(X) - \mu_0(X)] has the orthogonal score ψ=φ(W;μ0,μ1,e)−τ\psi = \varphi(W; \mu_0, \mu_1, e) - \tau, where φ\varphi is the AIPW pseudo-outcome of section 3.2. The DML recipe gives

    τ^AIPW=1n∑i=1nφ^i,SE^=sd(φ^1,…,φ^n)n,\hat\tau_{\mathrm{AIPW}} = \frac1n \sum_{i=1}^n \hat\varphi_i, \qquad \widehat{\mathrm{SE}} = \frac{\mathrm{sd}(\hat\varphi_1, \dots, \hat\varphi_n)}{\sqrt n},

    with μ^t\hat\mu_t and e^\hat e cross-fitted. This is the AIPW estimator of lesson 05, now with ML models and cross-fitting. The product form of its bias (section 3.2) gives the rate condition ∥e^−e∥2⋅∥μ^t−μt∥2=oP(n−1/2)\|\hat e - e\|_2 \cdot \|\hat\mu_t - \mu_t\|_2 = o_P(n^{-1/2}) for t=0,1t = 0, 1, plus e^\hat e bounded away from 0 and 1. Under it, τ^AIPW\hat\tau_{\mathrm{AIPW}} is asymptotically normal and reaches the smallest possible asymptotic variance (the semiparametric efficiency bound, Hahn 1998). In practice, clip e^\hat e to an interval such as [0.01,0.99][0.01, 0.99] and report how many units were affected.

    3.5 Causal trees and causal forests #

    A regression tree splits the covariate space into boxes (leaves) and predicts the mean of YY in each leaf. A causal tree (Athey and Imbens 2016) predicts the effect in each leaf: in a randomized experiment, the difference between the mean outcome of treated and control units in the leaf. Two changes make this work.

    1. Split to find different effects. A regression tree chooses the split that most reduces the squared error of YY. We cannot compute the squared error of τ\tau. Athey and Imbens show that, up to terms that do not depend on the split and a variance penalty, minimizing the expected squared error of τ^\hat\tau is the same as maximizing ∑leavesnleaf τ^leaf2\sum_{\text{leaves}} n_{\text{leaf}}\,\hat\tau_{\text{leaf}}^2. So a good split makes the effects of its two children as different as possible.

    2. Honesty. A tree is honest if one subsample chooses the splits and a separate subsample estimates the leaf effects. Why: the split search looks at many candidate splits and picks the one where the two sides look most different. Part of that difference is noise. If the same units then estimate the leaf effects, the noise stays in the estimates: the effects look more extreme than they are, and the usual confidence interval is too narrow. With honesty, the estimation units are fresh. Given the tree, the leaf difference in means is an unbiased estimate of the average effect in that leaf, and the usual interval τ^leaf±1.96s12/n1+s02/n0\hat\tau_{\text{leaf}} \pm 1.96\sqrt{s_1^2/n_1 + s_0^2/n_0} is valid.

    Interactive figure: loading…

    Compare adaptive and honest trees. The left square shows the true effect in four regions; the right square shows the tree's leaves, shaded by the estimated effect. Magenta outlines mark leaves whose 95% CI misses the true average effect of the leaf. Press Run 100 trees at depth 4 in each mode: the adaptive tree's intervals cover the truth only about 75–80% of the time, the honest tree's about 95%. Then compare the MSE at depth 2 and at depth 6: honesty costs accuracy for shallow trees (half the data per task), and it is about equal or slightly better for deep trees.

    Causal forests (Wager and Athey 2018) average many honest causal trees, each grown on a random subsample (drawn without replacement) and with random subsets of features at each split: τ^(x)=1B∑b=1Bτ^b(x)\hat\tau(x) = \frac1B\sum_{b=1}^B \hat\tau_b(x). Under conditions on the subsample size, the leaf sizes and the smoothness of τ\tau, they prove that τ^(x)\hat\tau(x) is consistent and asymptotically normal at each xx, with a variance that can be estimated (by the infinitesimal jackknife). So a causal forest gives a confidence interval for τ(x)\tau(x), which most ML methods cannot.

    Generalized random forests and the R-learner

    Forest weights. A forest defines how similar a training point XiX_i is to a target point xx: αi(x)=1B∑b1{Xi∈Lb(x)}∣Lb(x)∣\alpha_i(x) = \frac1B \sum_b \frac{\mathbf 1\{X_i \in L_b(x)\}}{|L_b(x)|}, where Lb(x)L_b(x) is the leaf of tree bb that contains xx. The weights are non-negative and add up to 1. A random forest prediction is ∑iαi(x)Yi\sum_i \alpha_i(x) Y_i: an adaptive nearest-neighbor average.

    Generalized random forests (Athey, Tibshirani and Wager 2019) use these weights to solve a local moment equation ∑iαi(x) ψθ(x)(Oi)=0\sum_i \alpha_i(x)\,\psi_{\theta(x)}(O_i) = 0 for any estimating equation ψ\psi. For the CATE, the grf causal forest first computes out-of-bag nuisance estimates ℓ^(Xi)\hat\ell(X_i) and e^(Xi)\hat e(X_i) ("local centering"), then solves the residual-on-residual equation of section 3.3 locally:

    τ^(x)=∑iαi(x) T~i Y~i∑iαi(x) T~i2,T~i=Ti−e^(Xi),  Y~i=Yi−ℓ^(Xi).\hat\tau(x) = \frac{\sum_i \alpha_i(x)\,\tilde T_i\,\tilde Y_i}{\sum_i \alpha_i(x)\,\tilde T_i^2}, \qquad \tilde T_i = T_i - \hat e(X_i),\; \tilde Y_i = Y_i - \hat\ell(X_i).

    So a causal forest is "double ML, solved separately near each xx, with neighbors chosen by a forest". The same machinery gives quantile forests, instrumental-variable forests and others. Exercise 4 of the notebook builds a small version with scikit-learn.

    R-learner (Nie and Wager 2021). Robinson's transformation also holds with a varying effect: if Y=μ0(X)+τ(X) T+εY = \mu_0(X) + \tau(X)\,T + \varepsilon, then Y−ℓ(X)=τ(X) (T−e(X))+εY - \ell(X) = \tau(X)\,(T - e(X)) + \varepsilon. So the true τ\tau minimizes the R-loss

    τ^=arg⁡min⁡τ  1n∑i=1n[(Yi−ℓ^(Xi))−τ(Xi) (Ti−e^(Xi))]2+Λ(τ),\hat\tau = \arg\min_\tau\; \frac1n\sum_{i=1}^n \Big[\big(Y_i - \hat\ell(X_i)\big) - \tau(X_i)\,\big(T_i - \hat e(X_i)\big)\Big]^2 + \Lambda(\tau),

    with cross-fitted ℓ^,e^\hat\ell, \hat e and any regularizer Λ\Lambda. Equivalently: regress the pseudo-outcome (Yi−ℓ^)/(Ti−e^)(Y_i - \hat\ell)/(T_i - \hat e) on XiX_i with sample weights (Ti−e^)2(T_i - \hat e)^2, with any ML method that accepts weights. Nie and Wager prove a quasi-oracle property: with nuisance errors of order o(n−1/4)o(n^{-1/4}), τ^\hat\tau has the same error rate as if ℓ\ell and ee were known. The R-loss is also a way to compare CATE models on validation data.

    3.6 Evaluating a CATE model without ground truth #

    For a prediction model we compute the test error. For a CATE model we cannot: τi=Yi(1)−Yi(0)\tau_i = Y_i(1) - Y_i(0) is never observed (the fundamental problem of lesson 02). Four tools, all best used on a randomized held-out set (the propensity ee is known and there is no confounding):

    1. The transformed outcome. With known e(x)e(x), define

    Y∗=Y T−e(X)e(X) (1−e(X))={Y/e(X)if T=1,−Y/(1−e(X))if T=0.Y^* = Y\,\frac{T - e(X)}{e(X)\,(1 - e(X))} = \begin{cases} Y / e(X) & \text{if } T = 1, \\ -Y / (1 - e(X)) & \text{if } T = 0. \end{cases}

    Theorem. Under assumptions 1–3, E[Y∗∣X=x]=τ(x)\mathbb{E}[Y^* \mid X = x] = \tau(x).

    Proof. E[TY/e(X)∣X=x]=e(x) μ1(x)/e(x)=μ1(x)\mathbb{E}[TY/e(X) \mid X = x] = e(x)\,\mu_1(x)/e(x) = \mu_1(x) and E[(1−T)Y/(1−e(X))∣X=x]=μ0(x)\mathbb{E}[(1 - T)Y/(1 - e(X)) \mid X = x] = \mu_0(x). Subtract and use section 3.1. ■\blacksquare

    So Y∗Y^* is a noisy but unbiased "label" for the effect. For a model τ^\hat\tau fitted on other data, E[(Y∗−τ^(X))2]=E[(τ(X)−τ^(X))2]+E[(Y∗−τ(X))2]\mathbb{E}[(Y^* - \hat\tau(X))^2] = \mathbb{E}[(\tau(X) - \hat\tau(X))^2] + \mathbb{E}[(Y^* - \tau(X))^2] (the cross term vanishes because E[Y∗−τ(X)∣X]=0\mathbb{E}[Y^* - \tau(X) \mid X] = 0). The second term does not depend on the model. So the mean squared error against Y∗Y^* ranks models correctly, although its value is much larger than the true error. (The AIPW pseudo-outcome φ^\hat\varphi is a lower-variance label of the same kind.)

    2. Uplift and Qini curves. Sort the test units by τ^\hat\tau, from high to low. For the top kk units, compare the treated and control outcomes among them:

    U(k)=(YˉT(k)−YˉC(k))⋅k,Q(k)=(YˉT(k)−YˉC(k))⋅nT(k),U(k) = \big(\bar Y_{T}(k) - \bar Y_{C}(k)\big)\cdot k, \qquad Q(k) = \big(\bar Y_{T}(k) - \bar Y_{C}(k)\big)\cdot n_T(k),

    where YˉT(k)\bar Y_T(k) and YˉC(k)\bar Y_C(k) are the mean outcomes of the treated and control units among the top kk, and nT(k)n_T(k) is the number of treated among them. U(k)U(k) estimates the number of extra successes if we treat these kk units (the uplift curve); Q(k)Q(k) is the Qini curve of Radcliffe (2007), the same quantity counted in the treated group. A good model rises fast; random targeting is the straight line from 0 to U(n)U(n); the area between the curve and that line (the Qini coefficient) summarizes the model. Unlike a churn or response model, the uplift curve measures the effect of targeting.

    Interactive figure: loading…

    Choose a budget and a cost. A simulated shop ran a randomized coupon test on 20,000 customers. The oracle sorts by the true effects; the black uplift model is a noisy version of them; the response model sorts by the probability to buy with a coupon. Notice that the response model's curve first goes down: the likely buyers buy anyway, and the coupon slightly lowers the purchases of some of them. Move the budget slider and read the extra purchases. Raise the cost per coupon: the best budget moves left, to the point where the next customer's effect is smaller than the cost. Switch to the weak model to see a flatter curve.

    3. Calibration by groups. Sort the test units into, say, 5 groups by τ^\hat\tau. In each group, estimate the average effect (difference in means in an RCT, or the mean of φ^\hat\varphi) and compare it with the mean of τ^\hat\tau in the group. A useful model has group effects that increase from group 1 to group 5 and lie near the predictions. These group average treatment effects (GATES) come with confidence intervals, so the comparison is honest.

    4. The best linear predictor test (Chernozhukov, Demirer, Duflo and Fernández-Val). Treat the model's score S(X)=τ^(X)S(X) = \hat\tau(X) as a feature. The best linear predictor of τ(X)\tau(X) from SS is β1+β2 (S−ES)\beta_1 + \beta_2\,(S - \mathbb{E}S), with β1=τATE\beta_1 = \tau_{\mathrm{ATE}} and β2=Cov(τ,S)/Var(S)\beta_2 = \mathrm{Cov}(\tau, S)/\mathrm{Var}(S). Both can be estimated in an RCT by a linear regression of YY on a constant, T−eT - e and (T−e)(S−Sˉ)(T - e)(S - \bar S) (plus optional baseline controls), with weights 1/(e(1−e))1/(e(1 - e)). β2=0\beta_2 = 0 means the model found no heterogeneity that is real; β2=1\beta_2 = 1 means its scores have the right scale. A test of β2=0\beta_2 = 0 is a test for heterogeneity.

    From effects to decisions. If treating costs cc (in units of YY), the best rule given xx is "treat if τ(x)>c\tau(x) > c". The plug-in policy treats if τ^(x)>c\hat\tau(x) > c. Its value can be estimated on a randomized test set (lesson 11 does this for general policies). Athey and Wager (2021) learn a policy directly: choose a rule from a simple class (for example, a depth-2 tree) that maximizes the average AIPW score of the actions it takes. This gives rules that are easy to explain and come with regret guarantees.

    Quick check

    A team wants to report the mean squared error of their CATE model on last year's customer data, as they do for their churn model. Why is this not possible directly?

    3.7 A practical guide #

    1. Write the assumptions first. Draw the graph (lessons 03–04). Put only pre-treatment variables in XX. Causal ML adjusts only for what is in XX; it cannot fix a missing confounder (use the sensitivity analysis of lesson 05).
    2. Check overlap. Plot e^(x)\hat e(x) for treated and controls. With values near 0 or 1, AIPW and the DR-learner become unstable. Clip e^\hat e, restrict the population (and say so: the estimand changes), or use overlap weights.
    3. Nuisance models. Use strong prediction methods (gradient boosting, random forests, lasso with interactions) and tune them by cross-validation for prediction. For a binary TT, use a calibrated classifier for e^\hat e.
    4. Cross-fit with K=5K = 5 folds; repeat over a few random splits and report the median estimate.
    5. Report in this order: the ATE (AIPW or DML) with a confidence interval; a test for heterogeneity (BLP, GATES); then the CATE model, its uplift curve on held-out randomized data, and the policy it implies.
    6. Treat discovered subgroups as hypotheses. A forest searches many splits. Confirm a surprising subgroup on new data, ideally a new experiment.

    Answers to section 1. (1) No. The likely buyers may buy without a coupon, so the coupon adds little for them, and for some it can even lower purchases. Targeting should rank by the effect τ(x)\tau(x), estimated with an uplift model; the response model curve in the uplift figure shows the loss. (2) τ^\hat\tau is shrunk toward 0: this is the regularization bias of the S-learner (section 2.1). (3) Much smaller. In DML the nuisance errors enter only as a product (section 3.3), so two errors of about 10%10\% give a bias of the order of 10%×10%=1%10\% \times 10\% = 1\%. A plug-in estimator would carry the 10%10\% error directly.

    4. Worked example #

    A shop sends a coupon to some customers and measures spending YY in the next month. The only covariate is XX: X=0X = 0 for new customers, X=1X = 1 for returning customers. Returning customers were more likely to get the coupon. We assume that XX is the only confounder. The data, as cell sizes and mean spending:

    Cell nn mean YY
    X=0X = 0, coupon (T=1T = 1) 20 12
    X=0X = 0, no coupon (T=0T = 0) 80 10
    X=1X = 1, coupon 80 26
    X=1X = 1, no coupon 20 20

    Step 1: the naive comparison. Mean spending with a coupon: (20⋅12+80⋅26)/100=23.2(20 \cdot 12 + 80 \cdot 26)/100 = 23.2. Without: (80⋅10+20⋅20)/100=12(80 \cdot 10 + 20 \cdot 20)/100 = 12. Naive difference: 11.211.2. It is confounded: the coupon group is mostly returning customers, who spend more anyway.

    Step 2: the CATE (T-learner with cell means). τ^(0)=12−10=2\hat\tau(0) = 12 - 10 = 2 and τ^(1)=26−20=6\hat\tau(1) = 26 - 20 = 6. The coupon helps returning customers three times as much. With a discrete XX and one mean per cell, the S- (with an interaction), T-, X- and DR-learners all give these same two numbers; they differ only when models must smooth or extrapolate.

    Step 3: ATE and ATT. Both groups have 100 customers, so τ^ATE=0.5⋅2+0.5⋅6=4\hat\tau_{\mathrm{ATE}} = 0.5 \cdot 2 + 0.5 \cdot 6 = 4. The treated are 20 new and 80 returning customers, so τ^ATT=(20⋅2+80⋅6)/100=5.2\hat\tau_{\mathrm{ATT}} = (20 \cdot 2 + 80 \cdot 6)/100 = 5.2.

    Step 4: double ML by hand. The nuisance functions are cell averages.

    • e^(0)=20/100=0.2\hat e(0) = 20/100 = 0.2 and e^(1)=80/100=0.8\hat e(1) = 80/100 = 0.8.
    • ℓ^(0)=0.2⋅12+0.8⋅10=10.4\hat\ell(0) = 0.2 \cdot 12 + 0.8 \cdot 10 = 10.4 and ℓ^(1)=0.8⋅26+0.2⋅20=24.8\hat\ell(1) = 0.8 \cdot 26 + 0.2 \cdot 20 = 24.8.

    Residuals T~=T−e^(X)\tilde T = T - \hat e(X) and Y~=Y−ℓ^(X)\tilde Y = Y - \hat\ell(X). Inside a cell, T~\tilde T is the same for every unit, so ∑T~ Y~=n T~ (Yˉcell−ℓ^)\sum \tilde T\,\tilde Y = n\,\tilde T\,(\bar Y_{\text{cell}} - \hat\ell) (the individual noise around the cell mean sums to 0):

    Cell nn T~\tilde T Yˉcell−ℓ^\bar Y_{\text{cell}} - \hat\ell n T~ (Yˉcell−ℓ^)n\,\tilde T\,(\bar Y_{\text{cell}} - \hat\ell) n T~2n\,\tilde T^2
    X=0X = 0, T=1T = 1 20 0.80.8 12−10.4=1.612 - 10.4 = 1.6 25.625.6 12.812.8
    X=0X = 0, T=0T = 0 80 −0.2-0.2 10−10.4=−0.410 - 10.4 = -0.4 6.46.4 3.23.2
    X=1X = 1, T=1T = 1 80 0.20.2 26−24.8=1.226 - 24.8 = 1.2 19.219.2 3.23.2
    X=1X = 1, T=0T = 0 20 −0.8-0.8 20−24.8=−4.820 - 24.8 = -4.8 76.876.8 12.812.8
    sum 128128 3232

    So θ^=128/32=4\hat\theta = 128/32 = 4. Check with the formula of the warning box in section 3.3: the weights are nx e^(x)(1−e^(x))=100⋅0.16=16n_x\,\hat e(x)(1 - \hat e(x)) = 100 \cdot 0.16 = 16 for both strata, so θ^=(16⋅2+16⋅6)/32=4\hat\theta = (16 \cdot 2 + 16 \cdot 6)/32 = 4. Here it equals the ATE because the two strata have the same weight. Check-yourself question 2 changes one number and shows that it does not always.

    Step 5: one AIPW pseudo-outcome. A returning customer without a coupon spent Y=17Y = 17. With μ^1(1)=26\hat\mu_1(1) = 26, μ^0(1)=20\hat\mu_0(1) = 20, e^(1)=0.8\hat e(1) = 0.8:

    φ^=26−20+0−17−201−0.8=6+15=21.\hat\varphi = 26 - 20 + 0 - \frac{17 - 20}{1 - 0.8} = 6 + 15 = 21 .

    One pseudo-outcome is far from the cell effect 6: the weight 1/(1−0.8)=51/(1 - 0.8) = 5 multiplies the residual by 5. But the residuals of the cell average to 0, so the mean of φ^\hat\varphi over the cell is exactly 6. This is why DR-learners need many units, or good overlap, to be stable.

    Step 6: an uplift curve with 8 units. A randomized test, units already sorted by τ^\hat\tau from high to low; TT = coupon, YY = bought (1) or not (0):

    rank 1 2 3 4 5 6 7 8
    TT 1 0 1 0 1 0 1 0
    YY 1 0 1 0 0 0 0 1
    • Top 2: treated YˉT=1\bar Y_T = 1, control YˉC=0\bar Y_C = 0; U(2)=(1−0)⋅2=2U(2) = (1 - 0) \cdot 2 = 2.
    • Top 4: YˉT=2/2=1\bar Y_T = 2/2 = 1, YˉC=0/2=0\bar Y_C = 0/2 = 0; U(4)=4U(4) = 4.
    • Top 6: YˉT=2/3\bar Y_T = 2/3, YˉC=0/3=0\bar Y_C = 0/3 = 0; U(6)=(2/3)⋅6=4U(6) = (2/3) \cdot 6 = 4.
    • All 8: YˉT=2/4\bar Y_T = 2/4, YˉC=1/4\bar Y_C = 1/4; U(8)=(1/4)⋅8=2U(8) = (1/4) \cdot 8 = 2.

    The curve is 0,2,4,4,20, 2, 4, 4, 2: treating the top half gives about 4 extra purchases, treating more adds nothing and then loses. If a coupon costs 0.30.3 purchases, the net gain is 4−4⋅0.3=2.84 - 4 \cdot 0.3 = 2.8 for the top half and 4−6⋅0.3=2.24 - 6 \cdot 0.3 = 2.2 for the top 75%. So we treat the top half. (With 8 units these numbers are very noisy; real uplift curves need thousands of units, as in the figure.)

    5. In code #

    NumPy and scikit-learn check the worked example and run DML with random forests on simulated data.

    import numpy as np
    from sklearn.ensemble import RandomForestRegressor
    from sklearn.model_selection import KFold
    
    # (a) the two-stratum example: cell sizes and cell means of Y
    n  = {(0, 1): 20, (0, 0): 80, (1, 1): 80, (1, 0): 20}      # (X, T): count
    ym = {(0, 1): 12., (0, 0): 10., (1, 1): 26., (1, 0): 20.}  # (X, T): mean Y
    x = np.concatenate([[k[0]] * v for k, v in n.items()])
    t = np.concatenate([[k[1]] * v for k, v in n.items()]).astype(float)
    dev = np.concatenate([np.resize([-1., 1.], v) for v in n.values()])   # noise that averages to 0 in each cell
    y = np.array([ym[(a, int(b))] for a, b in zip(x, t)]) + dev
    
    tau_hat = {s: float(y[(x == s) & (t == 1)].mean() - y[(x == s) & (t == 0)].mean()) for s in (0, 1)}
    e_hat = {s: float(t[x == s].mean()) for s in (0, 1)}
    print(tau_hat, e_hat)                                  # {0: 2.0, 1: 6.0} {0: 0.2, 1: 0.8}
    print(round(y[t == 1].mean() - y[t == 0].mean(), 3))   # 11.2  (naive)
    print(np.mean([tau_hat[s] for s in x]))                # 4.0   (ATE)
    print(np.mean([tau_hat[s] for s in x[t == 1]]))        # 5.2   (ATT)
    
    # residual on residual, with the cell averages as nuisance functions
    t_res = t - np.array([e_hat[s] for s in x])
    l_hat = {s: y[x == s].mean() for s in (0, 1)}
    y_res = y - np.array([l_hat[s] for s in x])
    print(round(t_res @ y_res, 3), round(t_res @ t_res, 3), round((t_res @ y_res) / (t_res @ t_res), 3))
    # 128.0 32.0 4.0
    
    # (b) double ML with random forests and 2-fold cross-fitting on simulated data
    rng = np.random.default_rng(0)
    N = 2000
    X = rng.normal(size=(N, 5))
    m = np.tanh(2 * X[:, 0]) + 0.5 * X[:, 1]                 # E[T | X]
    g = 2 * np.tanh(2 * X[:, 0]) + np.sin(2 * X[:, 1])       # effect of X on Y
    T = m + rng.normal(size=N)
    Y = 0.5 * T + g + rng.normal(size=N)                      # true theta = 0.5
    
    print(round(np.polyfit(T, Y, 1)[0], 3))                    # 1.245  (naive slope, confounded)
    l_hat_, m_hat_ = np.zeros(N), np.zeros(N)
    for train, test in KFold(2, shuffle=True, random_state=0).split(X):
        rf = dict(n_estimators=200, min_samples_leaf=5, random_state=0)
        l_hat_[test] = RandomForestRegressor(**rf).fit(X[train], Y[train]).predict(X[test])
        m_hat_[test] = RandomForestRegressor(**rf).fit(X[train], T[train]).predict(X[test])
    Tt, Yt = T - m_hat_, Y - l_hat_
    theta = (Tt @ Yt) / (Tt @ Tt)
    se = np.sqrt(np.sum(Tt**2 * (Yt - theta * Tt) ** 2)) / (Tt @ Tt)
    print(round(theta, 3), round(se, 3))                       # 0.514 0.022
    
    # (c) one AIPW pseudo-outcome: a control unit in stratum X = 1 with Y = 17
    mu1, mu0, e = 26., 20., 0.8
    print(round(mu1 - mu0 - (17 - mu0) / (1 - e), 3))         # 21.0
    
    # (d) uplift curve of 8 randomized units, already sorted by predicted effect
    tt = np.array([1, 0, 1, 0, 1, 0, 1, 0]); yy = np.array([1, 0, 1, 0, 0, 0, 0, 1])
    for k in (2, 4, 6, 8):
        a, b = tt[:k] == 1, tt[:k] == 0
        print(k, float((yy[:k][a].mean() - yy[:k][b].mean()) * k))   # 2 2.0 / 4 4.0 / 6 4.0 / 8 2.0
    

    The DML estimate 0.5140.514 has a 95% interval of about [0.47,0.56][0.47, 0.56], which contains the true 0.50.5; the naive slope 1.2451.245 is far off. The notebook adds the plug-in estimator, repeats the experiment over many seeds, and builds the meta-learners, a small causal forest and an uplift curve.

    6. Where it shows up #

    • Uplift modeling and targeting. Coupons, retention offers, notifications and ads are sent to the customers with the largest estimated effect, not the largest purchase or churn probability. Models are trained on randomized campaigns and evaluated with Qini curves.
    • Heterogeneous effects in A/B tests. Large online experiments report the ATE and then look for segments (new vs returning users, device, country) where the effect differs, with causal forests or the BLP/GATES tests, and with care about multiple testing.
    • Medicine. Causal forests and DR-learners on trial or registry data estimate which patients benefit most from a treatment, and which ones carry risk without benefit.
    • Economics and policy. DML is standard for effects with many controls: the original paper estimates the effect of 401(k) eligibility on savings; later work uses it for price elasticities and labour-market programs. Causal forests target job-training and welfare programs.
    • Machine learning for science. In agriculture and ecology, the effect of an intervention (fertilizer, irrigation, a conservation policy) depends on soil, weather and location; causal forests map where it helps. In climate and Earth science, DML-style partialling out is used to separate the effect of one driver from many correlated background variables.

    7. Common mistakes #

    • Targeting with a response or churn model. It ranks by the outcome, not by the effect. The people most likely to buy or to stay are often the ones the treatment changes least. Use an uplift model and check it with an uplift curve on randomized data.
    • Reading the effect from an S-learner with strong regularization. The model can ignore TT, and τ^\hat\tau shrinks toward 0. Compare with a T-, X- or DR-learner, and check that TT is actually used.
    • No cross-fitting. Residuals from nuisance models that saw the same units are too small and correlated with the noise: biased θ^\hat\theta and too narrow intervals. Always predict each unit with a model trained on other folds.
    • "ML handles confounding." DML and causal forests adjust only for the measured XX. An unmeasured confounder biases them as much as it biases regression. Use domain knowledge and a sensitivity analysis (lesson 05).
    • Many features, including bad controls. Putting post-treatment variables (mediators, colliders) into XX "because the model can handle it" breaks identification (lessons 03–04). Only pre-treatment covariates belong in XX.
    • Reporting the partially linear θ\theta as the ATE when effects vary. It is an overlap-weighted average (section 3.3). For the ATE use AIPW.
    • Ignoring overlap. With e^\hat e near 0 or 1, pseudo-outcomes explode. Check the histogram of e^\hat e, and clip or restrict, saying how the estimand changes.
    • Evaluating a CATE model in-sample, or with YY as the label. Use a held-out randomized set, the transformed outcome, uplift curves and group effects.

    8. Check yourself #

    1. In an X-learner, at some xx: e^(x)=0.1\hat e(x) = 0.1, τ^0(x)=3\hat\tau_0(x) = 3, τ^1(x)=1\hat\tau_1(x) = 1. Compute τ^(x)\hat\tau(x), and say why the X-learner trusts τ^1\hat\tau_1 more here.
      Answerτ^(x)=0.1⋅3+0.9⋅1=1.2\hat\tau(x) = 0.1 \cdot 3 + 0.9 \cdot 1 = 1.2. Only 10% of units like this are treated. τ^1\hat\tau_1 uses the imputed effects Yi−μ^0(Xi)Y_i - \hat\mu_0(X_i) of the treated, where μ^0\hat\mu_0 is fitted on the large control group and is accurate. τ^0\hat\tau_0 uses μ^1\hat\mu_1, which is fitted on few points and is less accurate.
    2. Change the worked example: among returning customers, 50 get the coupon (mean spending 26) and 50 do not (mean 20). Nothing else changes. What do the ATE and the partially linear DML estimate become?
      AnswerThe CATEs stay 22 and 66, so the ATE stays 44. Now e^(1)=0.5\hat e(1) = 0.5, so the weights are 100⋅0.16=16100 \cdot 0.16 = 16 for new and 100⋅0.25=25100 \cdot 0.25 = 25 for returning customers: θ^=(16⋅2+25⋅6)/41=182/41≈4.44\hat\theta = (16 \cdot 2 + 25 \cdot 6)/41 = 182/41 \approx 4.44. The partially linear estimate gives more weight to the stratum where the treatment varies more. It is not the ATE when effects differ.
    3. In an RCT with e=0.5e = 0.5, compute the transformed outcome Y∗Y^* for a treated unit with Y=1Y = 1, a treated unit with Y=0Y = 0 and a control unit with Y=1Y = 1. Why can single values of Y∗Y^* be far from any plausible effect?
      AnswerY∗=Y(T−e)/(e(1−e))=Y(T−0.5)/0.25Y^* = Y(T - e)/(e(1 - e)) = Y(T - 0.5)/0.25: treated with Y=1Y = 1 gives 22; treated with Y=0Y = 0 gives 00; control with Y=1Y = 1 gives −2-2. Each Y∗Y^* uses one outcome only, so it is very noisy. Only its conditional mean equals τ(x)\tau(x). That is why it ranks models correctly on average but its MSE level is large.
    4. Does cross-fitting with K=5K = 5 folds mean that the final estimate uses only one fifth of the data?
      AnswerNo. Every unit gets residuals from models trained on the other four folds, and θ^\hat\theta pools all nn units. Every unit is also used to train the nuisance models for the other folds. The only cost is that each nuisance model is trained on 80%80\% of the data.
    5. At depth 2, the honest tree in the figure has a larger MSE than the adaptive tree; at depth 6, a smaller one. Explain both.
      AnswerHonest trees use half the units to choose splits and half to estimate effects, so each part is noisier: at depth 2 this loss dominates. Deep adaptive trees choose many splits on noise and then estimate the leaves on the same noise, so their leaf effects are too extreme; this overfitting dominates at depth 6. Coverage is the clearer difference: about 95% for honest leaves, about 75–80% for adaptive leaves.
    6. A DML analysis with random forests gives θ^=0.51\hat\theta = 0.51 (SE 0.020.02); OLS of YY on TT and XX gives 0.900.90. Which assumptions must hold before you call 0.510.51 the causal effect?
      AnswerNo unmeasured confounding given XX (conditional exchangeability), only pre-treatment covariates in XX, consistency, and enough variation of TT given XX (overlap, E[Var(T∣X)]>0\mathbb{E}[\mathrm{Var}(T \mid X)] > 0). The partially linear form must hold, or 0.510.51 must be read as the weighted average θ∗\theta^*. The nuisance models must be good enough for the rate condition. The difference from OLS suggests nonlinear confounding that OLS missed.
    Recall cardsAnswer in your head first, then reveal. Add the cards to your review deck to see them again just before you would forget.
    1. Define the CATE and say when it equals μ1(x)−μ0(x)\mu_1(x) - \mu_0(x).

    2. Why does a regularized S-learner tend to underestimate effects?

    3. How does the X-learner combine its two effect models?

    4. Write the DML estimator for the partially linear model.

    5. What is Neyman orthogonality, in words?

    6. What does cross-fitting prevent?

    7. State the rate condition for DML in the partially linear model.

    8. What makes a causal tree "honest", and what does it buy?

    9. In an RCT with known e(x)e(x), what is the transformed outcome and its key property?

    10. What does an uplift curve show?

    Open the review →

    9. Interview angle #

    • "How would you decide which users get a discount?" — Not by purchase or churn probability. Run a randomized campaign (or use logged data with all confounders measured), estimate the CATE with an uplift model (X-/DR-learner, causal forest), evaluate it with an uplift/Qini curve on a randomized holdout, and treat users with τ^(x)\hat\tau(x) above the cost of the discount.
    • "What is double ML, and why cross-fit?" — Partial out XX from TT and YY with ML models and regress residual on residual. The score is Neyman orthogonal, so nuisance errors enter as a product and the estimate is n\sqrt n-consistent with a valid CI. Cross-fitting stops the nuisance models from fitting the noise of the units they are evaluated on.
    • "S-, T- or X-learner?" — S if the effect is small and data scarce (but it shrinks effects); T with plenty of data in both arms; X when the arms are unbalanced; DR or R when overlap is good and you want robustness and fast rates.
    • "How do you evaluate a CATE model if you never see individual effects?" — On a randomized holdout: uplift/Qini curves, calibration by groups (GATES), the BLP test, MSE against the transformed outcome for ranking models.
    • "Why are causal forests honest?" — To avoid choosing splits and estimating effects on the same noise; it makes leaf estimates unbiased given the tree and gives valid confidence intervals.

    10. Practice #

    The notebook for this lesson has five exercises, each with a check cell and a folded solution:

    1. Simulate data with a known τ(x)\tau(x) and build the S-, T- and X-learners with scikit-learn; compare their error against the truth with 10% and 50% treated.
    2. Write dml_plr with KK-fold cross-fitting and a standard error; compare the plug-in estimator, DML without cross-fitting and DML with cross-fitting over many seeds (bias and coverage).
    3. Build the DR-learner from cross-fitted AIPW pseudo-outcomes and check its ATE against the truth.
    4. Build a small honest causal forest: a random forest on one half gives the neighborhoods, and a weighted residual-on-residual regression on the other half gives τ^(x)\hat\tau(x).
    5. Compute an uplift curve on a simulated randomized test set and choose the best budget for a given cost per treatment.

    11. Watch and read #

    The CATE and the plan of the lecture: conditional outcome models, X-learner, double ML, causal trees.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The S-learner and the T-learner, and why the S-learner can ignore the treatment.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The X-learner step by step and its weighting by the propensity score.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    A short overview of doubly robust estimation, double ML and causal trees.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    The author of DML explains regularization bias, Neyman orthogonality and cross-fitting.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Honest causal trees, causal forests and policy learning, from one of their authors.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Causal forests and generalized random forests in more depth.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play
    Meta-learners for uplift and how to read uplift and cumulative gain curves in practice.
    Open on YouTube · the player loads from youtube-nocookie.com when you press play