Traditionally mediation model can be represented in the following equations:
\[ Y = a W + b M + \epsilon_1 \tag{21.1}\]\[ M = c W + \epsilon_2 \tag{21.2}\]
That is, we’d like to study the effect of \(W\) on \(Y\), and we see the effect can be a direct effect, and an indirect effect, through \(M\).
Baron and Kenny’s (http://davidakenny.net/cm/mediate.htm) method is done in four steps. Modern approach tends to use SEM (structural equation modeling) to model these two equations directly.
Code
usingRandomusingDataFramesusingStatsModelsusingLavaanRandom.seed!(1234)n =10000X =randn(n)M =0.5.* X .+randn(n)Y =0.7.* M .+0.3.* X .+randn(n)Data =DataFrame(X = X, M = M, Y = Y)model =""" Y ~ a*X + b*M M ~ c*X # direct effect (a) # indirect effect (b*c) bc := b*c # total effect total := a + (b*c)"""
" Y ~ a*X + b*M\n M ~ c*X\n # direct effect (a)\n # indirect effect (b*c)\n bc := b*c\n # total effect\n total := a + (b*c)\n"
Code
fit =sem(model, Data)fit
lavaan 0.1.0-dev fit object
Estimator: ML
Converged: Yes
χ²(1) = 999999999999999983222784.000 [p = 0.000]
Call summary() for full output.
21.1.1 Problems with Classical Mediation
Lack of causal claim. We have to assume that there is no unmeasured confounder between \(M\) and \(Y\). This is a strong assumption.
Assumption of homogeneous effect.
21.2 Causal Mediation
21.2.1 CDE
Suppose we can set \(W\) and \(M\) at will to any \((w, m)\), then we have the potential outcome \(Y(w,m)\).
Controlled direct effect (CDE) is defined as \[ CDE(m) = E[Y(1,m)-Y(0,m)] \tag{21.3}\] That is, setting \(M\) to \(m\), what is the effect of \(W\) on \(Y\)?
21.2.2 Assumptions
Conditional treatment randomization. Suppose we observe confounders X, which can be a joint set of confounders for the W to Y pathway, or the M to Y pathway.
\[ Y(w,m) \perp W|X \tag{21.4}\]
This is the usual conditional independence (unconfoundedness, ignorability, etc.) assumption. This is saying the assignment of treatment, given covariates \(X\), has nothing to do with potential outcomes.
Conditional mediator randomization.
\[ Y(w,m) \perp M|X, W=w \tag{21.5}\]
This is to say, within each strata of X, given treatment status, the assignment of mediator gives no information about potential outcome. This randomization is usually not implemented during many experiments (random trials). This is the assumption that makes a lot of mediation hard to make a causal claim.
Positivity (overlap). There are two positivity assumptions:
\[ P(W=w | X=x) > 0 \tag{21.6}\] for all \(x\). This is the usual positivity assumption.
\[ P(M=m | X=x, W=w) > 0 \tag{21.7}\] for all \(x\), \(w\), and \(m\). This is the mediator positivity.
21.2.3 Estimation
CDE can be estimated using G-computation method, or IPW, or the doubly-robust methods, one of them is AIPW (augmented IPW).
21.2.4 G-computation
G-computation is to model the outcome equation: \[
\begin{aligned}
CDE_G(m) &= \sum_x [ E[Y \mid W=1, M=m, X=x] \\
&\quad - E[Y \mid W=0, M=m, X=x]]\, P(X=x)
\end{aligned}
\tag{21.8}\]
21.2.5 IPW
IPW is to model the treatment assignment equation and the mediator assignment equation. The joint denominator factorizes sequentially – treatment given covariates, then mediator given treatment and covariates – which is the structure the estimator below uses:
\[ \small
CDE_{ipw}(m) = E\left[\frac{I(W=1,M=m)}{g_M(m|1,X)\,g_W(1|X)}\, Y - \frac{I(W=0,M=m)}{g_M(m|0,X)\,g_W(0|X)}\, Y\right]
\tag{21.10}\]
where \(g_M\) is the probability of the mediator and \(g_W\) the probability of treatment. This indicator-based form applies to a discrete (here binary) mediator. For a continuous mediator the indicator \(I(M=m)\) and probability \(g_M\) must be replaced by a conditional density (or a kernel / stochastic-intervention formulation); the estimator does not apply as written.
21.2.6 AIPW
\[ CDE_{AIPW} = CDE_G(m) + B(\bar Q, g_M, g_W) \tag{21.11}\] where \(\bar Q\) is the mean outcome function.
usingGLMusingDistributionsusingStatsFunsusingStatisticsRandom.seed!(1234)n =5000# confounder of A/YW1 =randn(n)# confounder of M/YW2 =randn(n)# treatmentA =rand.(Bernoulli.(logistic.(-1.+ W1 ./2)))# binary mediatorM =rand.(Bernoulli.(logistic.(-2.+ A ./2.+ W2 ./3)))# binary outcomeY =rand.(Bernoulli.(logistic.(-1.+ A .- M ./2.+ W1 ./3.+ W2 ./3)))full_data =DataFrame(W1 = W1, W2 = W2, A = A, M = M, Y = Y)# fit outcome regressionor_fit =glm(@formula(Y ~ A + M + W1 + W2), full_data, Binomial(), LogitLink())# new data setting A and Mdata_A1_M0 =copy(full_data)data_A0_M0 =copy(full_data)data_A1_M0.A .=1; data_A1_M0.M .=0data_A0_M0.A .=0; data_A0_M0.M .=0# predict on new dataQbar_A1_M0 =predict(or_fit, data_A1_M0)Qbar_A0_M0 =predict(or_fit, data_A0_M0)# gcomp estimate of CDE(0)cde_gcomp =mean(Qbar_A1_M0 .- Qbar_A0_M0)@printf"CDE(0) G-computation = %.4g\n" cde_gcomp
CDE(0) G-computation = 0.2113
21.2.8 Example: IPW
Code
# model for P(A = 1 | W)ps_fit1 =glm(@formula(A ~ W1 + W2), full_data, Binomial(), LogitLink())P_A1_W =predict(ps_fit1)P_A0_W =1.- P_A1_W# model for P(M = 0 | A, W)ps_fit2 =glm(@formula(M ~ A + W1 + W2), full_data, Binomial(), LogitLink())# P(M = 0 | A = 1, W)data_A1 =copy(full_data); data_A1.A .=1P_M0_A1_W =1.-predict(ps_fit2, data_A1)# P(M = 0 | A = 0, W)data_A0 =copy(full_data); data_A0.A .=0P_M0_A0_W =1.-predict(ps_fit2, data_A0)# ipw estimate of CDE(0)cde_ipw =mean( (A .==1) ./ P_A1_W .* (M .==0) ./ P_M0_A1_W .* Y ) -mean( (A .==0) ./ P_A0_W .* (M .==0) ./ P_M0_A0_W .* Y )@printf"CDE(0) IPW = %.4g\n" cde_ipw
21.3 NIE and NDE: Natural Direct and Indirect Effects
CDE is to study the effect of treatment, given the level of mediator. Instead, Natural Effect is to set mediator to its natural value with the value of treatment, that is, \(M=M(w)\).
\[
\begin{aligned}
ATE &= NIE + NDE \\
&= (E[Y(1,M(1))] - E[Y(1,M(0))]) \\
&\quad + (E[Y(1, M(0))] - E[Y(0,M(0))])
\end{aligned}
\tag{21.13}\]
The advantage of NDE and NIE comparing to CDE is that it’s more “natural”; that is, you don’t set the level of mediator deterministically. And it can decompose the ATE into direct and indirect effects.
However, there is an additional assumption needed to identify NDE and NIE.
21.3.1 Additional Assumption
\[ Y(w, m) \perp M(w^*) | X \tag{21.14}\]
This is the “cross-world” condition: the outcome under \((w,m)\) is independent of \(M\) under \(w^*\). These two situations cannot happen in the same world; you cannot set \(W\) to both \(w\) and \(w^*\). No experiment can implement it.
This cross-world independence is additional to, not a substitute for, the usual identifying assumptions. The standard mediation formula for natural effects also requires:
treatment ignorability (no unmeasured treatment-outcome confounding) given \(X\);
mediator ignorability (no unmeasured mediator-outcome confounding) given \(W\) and \(X\);
positivity for both treatment and mediator; and
no treatment-induced confounding of the mediator-outcome relationship – no variable affected by \(W\) may confound \(M\) and \(Y\). (When such a confounder exists, natural effects are not identified by this formula; interventional direct/indirect effects are used instead.)
Cross-world independence alone is not sufficient.
21.3.2 Estimation
Code
# fit outcome regression (include interaction because we can)or_fit =glm(@formula(Y ~ A + M + W1 + W2 + A&M + M&W1), full_data, Binomial(), LogitLink())# need E(Y | A = 0/1, M = 0/1, W1 = W1i, W2 = W2i)functionget_EY_a_m_Wi(full_data, or_fit, a, m) data_Aa_Mm_Wi =copy(full_data) data_Aa_Mm_Wi.A .= a data_Aa_Mm_Wi.M .= mpredict(or_fit, data_Aa_Mm_Wi)endEY_A0_M0_Wi =get_EY_a_m_Wi(full_data, or_fit, 0, 0)EY_A0_M1_Wi =get_EY_a_m_Wi(full_data, or_fit, 0, 1)EY_A1_M0_Wi =get_EY_a_m_Wi(full_data, or_fit, 1, 0)EY_A1_M1_Wi =get_EY_a_m_Wi(full_data, or_fit, 1, 1)# include interactions -- why not? (NOTE: A*W1 expands to A + W1 + A&W1, so# the MAIN effects are included. Writing only A&W1 would omit the main effect# of A and force the estimated NIE to be essentially zero by construction.)med_fit =glm(@formula(M ~ A*W1 + W1*W2), full_data, Binomial(), LogitLink())# estimates of P(M = m | A = a, W = W_i)functionget_Pm_a_Wi(full_data, med_fit, a, m) data_Aa_Wi =copy(full_data) data_Aa_Wi.A .= a p =predict(med_fit, data_Aa_Wi)if m ==1return pelsereturn1.- pendendPM0_A0_Wi =get_Pm_a_Wi(full_data, med_fit, 0, 0)PM1_A0_Wi =get_Pm_a_Wi(full_data, med_fit, 0, 1)PM0_A1_Wi =get_Pm_a_Wi(full_data, med_fit, 1, 0)PM1_A1_Wi =get_Pm_a_Wi(full_data, med_fit, 1, 1)# E(E(Y | A = 1, M, W) | A = 1, W)EY1M1_Wi = EY_A1_M1_Wi .* PM1_A1_Wi .+ EY_A1_M0_Wi .* PM0_A1_Wi# E(E(Y | A = 0, M, W) | A = 1, W)EY0M1_Wi = EY_A0_M1_Wi .* PM1_A1_Wi .+ EY_A0_M0_Wi .* PM0_A1_Wi# E(E(Y | A = 1, M, W) | A = 0, W)EY1M0_Wi = EY_A1_M1_Wi .* PM1_A0_Wi .+ EY_A1_M0_Wi .* PM0_A0_Wi# E(E(Y | A = 0, M, W) | A = 0, W)EY0M0_Wi = EY_A0_M1_Wi .* PM1_A0_Wi .+ EY_A0_M0_Wi .* PM0_A0_Wi# estimate of E[Y(1, M(1))]E_Y1M1 =mean(EY1M1_Wi)# estimate of E[Y(0, M(1))]E_Y0M1 =mean(EY0M1_Wi)# estimate of E[Y(1, M(0))]E_Y1M0 =mean(EY1M0_Wi)# estimate of E[Y(0, M(0))]E_Y0M0 =mean(EY0M0_Wi)# NDE = E[Y(1,M(0))] - E[Y(0,M(0))], NIE = E[Y(1,M(1))] - E[Y(1,M(0))]@printf"NDE = %.4g\n" (E_Y1M0 - E_Y0M0)@printf"NIE = %.4g\n" (E_Y1M1 - E_Y1M0)@printf"ATE = %.4g\n" (E_Y1M1 - E_Y0M0)
NDE = 0.2093
NIE = -0.01266
ATE = 0.1966
21.4 IIE and IDE: Interventional Direct and Indirect Effects
People are not happy with the cross-world assumption in general. Interventional effects avoid it. The device is a random draw: instead of the unit’s own \(M(w^*)\), use \(M^*_{w^*}\), a draw from the distribution of \(M(w^*)\) given \(X = x\). Effects defined through such draws are identified without the cross-world assumption, even when a treatment-induced confounder \(Z\) sits between treatment and mediator — the situation in the example below.
One subtlety matters. The plain randomized-interventional decomposition (available in Crumble.jl as effect = "RI") uses the draw in every term; its direct and indirect effects sum to an “overall interventional effect” that need not equal the ATE when \(Z\) is present, because the random draw breaks the within-unit dependence between \(M\) and \(Y\). The recanting twins construction (effect = "RT", used below) is built precisely to repair this: it decomposes the actual ATE,
into direct and indirect components by walking a path of intermediate “twin” regimes for \(Z\) and \(M\), each identified without cross-world independence. With effect = "RT", the printed \(IDE + IIE\) adds up to the ATE by construction.
Warning
Two caveats on the numbers below, both about Crumble.jl rather than about the estimand. First, the direct and indirect standard errors are combined as \(\sqrt{se_a^2 + se_b^2}\). That treats two estimators computed on the same sample as independent, so it ignores their covariance; the correct standard error comes from the variance of the difference of the influence curves, not from adding their variances. Second, the "RT" path currently computes both the natural and the randomized influence curves and then combines only the natural ones, so what is reported is not yet the recanting-twins decomposition described above — the identity \(IDE + IIE = ATE\) holds arithmetically, because all three are built from the same three regime means, but it holds for the natural decomposition.
Read the point estimates as an illustration of the workflow. For interventional effects to lean on, the medoutcon output in the R companion chapter is the better reference.
21.4.1 Example
Code
usingDataFramesusingStatsModelsusingRandomusingStatsFunsusingDistributionsusingCrumbleRandom.seed!(1584)# produces a simple data set based on a causal model with mediationfunctionmake_example_data(n_obs =1000)# baseline covariates w_1 =rand.(Bernoulli(0.6), n_obs) w_2 =rand.(Bernoulli(0.3), n_obs) w_3_prob =min.(0.2.+ (w_1 .+ w_2) ./3, 1.0) w_3 =rand.(Bernoulli.(w_3_prob))# exposure a_prob =logistic.(w_1 .+ w_2 .+ w_3 .-2) a =rand.(Bernoulli.(a_prob))# mediator-outcome confounder affected by treatment z_prob =logistic.(-log(2) .- a .+ (w_1 .+ w_2 .+ w_3) ./3.+0.2) z =rand.(Bernoulli.(z_prob))# mediator -- could be multivariate m_prob =logistic.(log(3) .* (w_1 .+ w_2) .+2.* a .-2.* z) m =rand.(Bernoulli.(m_prob))# outcome y_prob =logistic.(1./ (w_1 .+ w_2 .+ w_3 .- z .+ a .+ m)) y =rand.(Bernoulli.(y_prob))# construct output dat =DataFrame(W_1 = w_1, W_2 = w_2, W_3 = w_3, A = a, Z = z, M = m, Y = y)return datend
make_example_data (generic function with 2 methods)
Code
# set seed and simulate example dataexample_data =make_example_data()w_names = ["W_1", "W_2", "W_3"]m_names = ["M"]# quick look at the datafirst(example_data, 6)
6×7 DataFrame
Row
W_1
W_2
W_3
A
Z
M
Y
Bool
Bool
Bool
Bool
Bool
Bool
Bool
1
false
true
false
false
false
true
true
2
false
false
false
false
false
true
true
3
false
false
false
false
false
true
true
4
false
false
false
false
false
true
true
5
true
false
false
false
false
false
true
6
true
true
true
true
true
true
false
Code
# Estimate interventional direct and indirect effects using Crumble.jl# effect = "RT" is the recanting twin estimand, which gives IDE and IIE# while handling Z (mediator-outcome confounder affected by treatment)result =crumble(example_data, ["A"]; outcome ="Y", mediators = m_names, moc = ["Z"], # post-treatment confounder Z covar = w_names, effect ="RT", # recanting twin learners = ["glm"])result