10Counterfactuals: Unit-Level Alternatives at Structural Level
Status: Draft
v0.6
10.1 Introduction
Counterfactuals ask what would have happened for this unit under an alternative intervention (Pearl 2009; Imbens and Rubin 2015). That is Pearl’s third rung: not “what happens on average if we do \(a\)?” (rung 2), but “given what we saw for unit \(i\), what would \(Y\) have been under \(do(a')\)?”
At the Structural level the machinery is an SCM \((G,F,P(\mathbf{U}))\) plus Pearl’s three-step procedure: abduction (recover the unit’s exogenous realisation \(\mathbf{u}\)), action (apply \(do(\cdot)\)), prediction (re-simulate with the same \(\mathbf{u}\)). CausalDynamics.jl packages the last two steps in compute_counterfactual once \(\mathbf{u}\) is in hand; Chapter 4 already showed a short chain example. This chapter slows that process down, with graphs and arithmetic at each step.
NotePackages implement the examples
This book’s framing is general: structure, dynamics, and observation for complex dynamical systems. Executable examples use a Julia stack, CausalDynamics.jl (identify), CausalTargeted.jl (estimate LMTP / mediation), DAGMakie.jl (display). The book is not package documentation; manuals and changelogs live in the repositories.
Code keeps standard Pearl / targeted-learning names (Intervention, do_surgery, backdoor_adjustment_set, run_lmtp_grid, …). Prose may use a sparse process gloss where it helps: prehension (taking account of), shared \(U\) as creative advance (Introduction), L3 alternative concrescences, and Chapter 9’s organism / environment / Markov blanket / society vocabulary for CDM scope (\(\mu\), \(\eta\), \(s\), \(a\), \(G\), \(F\)). Prefer ordinary words (observation, intervention, time step) elsewhere. Mapping: Concept Reference, Tables 4 and 8.
Package source as notation. Where the implementation is the explanation (graph surgery, path blocking, shared-\(U\) counterfactuals), chapters may show a short, syntax-highlighted excerpt from the owned packages in a “From …jl” callout, alongside executed API chunks. Those excerpts are curated under snippets/package-source/; they are not a substitute for the Documenter manuals.
The same structural map \(F\) and graph \(G\) appear in both queries; only whether \(\mathbf{u}\) is integrated out or held fixed changes the estimand. Process gloss: fixed \(\mathbf{u}\) is the creative advance of one organism; different \(do(\cdot)\) yields an alternative concrescence (Table 8).
10.3 Pearl’s three steps
Pearl (Pearl 2009, Ch.~7) factors every structural counterfactual into:
Abduction — Infer \(\mathbf{u}\) (or a posterior over \(\mathbf{u}\)) from evidence in the factual world.
Action — Replace the assignment for the intervened variable(s) by a constant; mutilate incoming edges (modularity).
Prediction — Evaluate the mutilated SCM with the same\(\mathbf{u}\).
NoteFrom CausalDynamics.jl
Structural counterfactuals are three lines once abduction has fixed \(\mathbf{u}\): simulate the factual world, mutilate the graph under \(do(\cdot)\), then simulate again with the same exogenous values.
Shared exogenous_values is the creative advance held fixed; only the intervened mechanism changes. Discrete-time CDMs use the same idea via counterfactual(cdm, factual.noise; …) (Chapter 28).
The rest of the chapter walks a single ecological unit through these three steps, then notes what fails when confounders stay latent.
10.4 Worked example: one site, one “what if”
Use the rainfall–herbivore–richness DAG from the interventions practical (Modern Inference): rainfall \(R\) affects herbivore pressure \(H\) and species richness \(S\), and \(H\) also affects \(S\):
\[
\begin{aligned}
R &\coloneqq U_R, \\
H &\coloneqq a R + U_H, \\
S &\coloneqq b R + c H + U_S,
\end{aligned}
\]
with numeric weights \(a=0.5\), \(b=0.7\), \(c=0.4\). Site A is observed at \(R=0.5\), \(H=1\), \(S=1.5\). The counterfactual question is: what would Site A’s richness have been if herbivore pressure had been doubled (\(do(H=2)\))?
include(joinpath(dirname(Base.active_project()), "scripts", "book_bootstrap.jl"))@auto_using DAGMakie CairoMakie CausalDynamics Graphs# Nodes: 1=R, 2=H, 3=Sg =SimpleDiGraph(3)add_edge!(g, 1, 2) # R → Hadd_edge!(g, 1, 3) # R → Sadd_edge!(g, 2, 3) # H → Slabels = ["R", "H", "S"]layout = Point2f[Point2f(0.0, 1.0), Point2f(-1.0, 0.0), Point2f(1.0, 0.0)]a, b, c =0.5, 0.7, 0.4equations =Dict{Int, Function}(1=> (u) -> u,2=> (r, u) -> a * r + u,3=> (r, h, u) -> b * r + c * h + u,)scm =GraphSCM(g, equations, Set{Int}())# Observed Site A (factual world)R_obs, H_obs, S_obs =0.5, 1.0, 1.5
(0.5, 1.0, 1.5)
Factual DAG for Site A: rainfall \(R\), herbivores \(H\), richness \(S\). Structural path \(H\rightarrow S\) is the channel we will intervene on.
10.4.1 Step 1: Abduction
Solve the structural equations for the exogenous draws consistent with the observation. Because \(R\) has no parents, \(U_R = R_{\mathrm{obs}}\). Then
Abduction recovers unit-specific exogenous draws. \(U_R\), \(U_H\), and \(U_S\) are fixed for Site A and will be reused under \(do(H=2)\).
For a fully deterministic invertible SCM, abduction is this algebraic solve. With stochastic mechanisms one samples (or approximates) \(P(\mathbf{u}\mid \text{evidence})\). The same Site A observation under a soft Gaussian likelihood yields a posterior concentrated near \((U_H,U_S)=(0.75,0.75)\):
Stochastic abduction: joint posterior draws of \((U_H,U_S)\) for Site A under a soft Gaussian likelihood. The algebraic solution (cross) sits at the mode.
Push posterior draws of \(\mathbf{u}\) through action and prediction to get a counterfactual distribution, not a single number. For Quarto speed we keep \(400\) NUTS draws (\(\approx 10\,\mathrm{ms}\) after warmup in local benchmarks).
10.4.2 Step 2: Action
Replace the assignment for \(H\) by the constant \(2\) and delete edges into \(H\) (here \(R\rightarrow H\)). Rainfall and the abduced noises are unchanged; only the herbivore mechanism is modularly replaced (Pearl 2009).
ι =do_intervention(2, 2.0) # do(H = 2)scm_cf =counterfactual_graph(scm, ι)println("Parents of H after surgery: ", collect(inneighbors(scm_cf.graph, 2)))println("S still has parents R and H: ", has_edge(scm_cf.graph, 1, 3) &&has_edge(scm_cf.graph, 2, 3))
Parents of H after surgery: Int64[]
S still has parents R and H: true
Action: factual DAG (left) versus mutilated DAG under \(do(H=2)\) (right). Incoming arrows to \(H\) are cut; \(S\) still depends on \(R\) and the fixed \(H\).
10.4.3 Step 3: Prediction
Simulate the mutilated model with the same\(\mathbf{u}\):
Equivalently, \(S_{\mathrm{cf}} = S_{\mathrm{obs}} + c(2 - H_{\mathrm{obs}}) = 1.5 + 0.4 = 1.9\): doubling herbivores adds one unit of \(c\) to richness for this site.
result =compute_counterfactual(scm, ι, U)S_fact = result.factual[3]S_cf = result.counterfactual[3]println("Factual S = ", S_fact)println("Counterfactual S under do(H=2) = ", S_cf)println("Individual effect Δ = ", S_cf - S_fact)@assert S_cf ≈1.9
Factual S = 1.5
Counterfactual S under do(H=2) = 1.9
Individual effect Δ = 0.3999999999999999
Prediction for Site A: observed richness versus counterfactual richness under \(do(H=2)\), same abduced \(\mathbf{u}\). The gap is the unit-level effect \(c\,(2-H_{\mathrm{obs}})=0.4\).
A population regression coefficient for \(H\) reports an average effect. The counterfactual above is tailored to Site A’s abduced \((U_H,U_S)\); another site with different residuals would move by the same structural \(c\cdot\Delta H\) only if mechanisms are linear and identical, but its levels would differ.
10.5 Shared \(\mathbf{u}\) is the unit
Nothing in the action or prediction steps redraws noise. If one sampled a fresh \(\mathbf{u}'\sim P(\mathbf{U})\) after intervening, the query would be interventional (rung 2), not counterfactual (rung 3). In code, that discipline is literally the shared exogenous_values dictionary passed to both simulate_scm calls inside compute_counterfactual.
10.6 When the graph blocks full identification
Abduction needs enough structure to recover (or constrain) \(\mathbf{u}\). If a latent confounder \(U\) sits on a backdoor between treatment and outcome and is never observed, unit-level counterfactuals are typically only partially identified: one can still report bounds or sensitivity parameters rather than a point value (Pearl 2009; Imbens and Rubin 2015).
# Latent U confounds A and Yg_lat =SimpleDiGraph(3)add_edge!(g_lat, 1, 2) # U → Aadd_edge!(g_lat, 1, 3) # U → Yadd_edge!(g_lat, 2, 3) # A → Yadj =backdoor_adjustment_set(g_lat, 2, 3)println("Minimal backdoor set for A→Y: ", adj) # {U}println("A ⫫ Y with empty conditioning? ", CausalDynamics.d_separated(g_lat, 2, 3, Int[]))# Given U, the backdoor is blocked, but the causal path A→Y remains open — so A ⫫̸ Y | U.# The identification problem is that U is latent: we cannot form that adjustment set from data.println("U observed in the graph? (node 1 is the confounder we treat as latent in prose)")
Minimal backdoor set for A→Y: Set([1])
A ⫫ Y with empty conditioning? false
U observed in the graph? (node 1 is the confounder we treat as latent in prose)
Latent confounder \(U\) on the backdoor \(A\leftarrow U\rightarrow Y\). The minimal backdoor set is \(\{U\}\); when \(U\) is unobserved, neither population adjustment nor unit-level abduction of \(U\) is available from \((A,Y)\) alone.
Practical posture when \(U\) is missing: state the identifying assumptions, report bounds or E-value-style sensitivity where appropriate, and avoid pretending a point counterfactual is identified from the observational margin alone.
10.7 Stratum context
This chapter is Imagining in the Structural layer: unit-level alternatives implied by an SCM. Related material elsewhere:
Dynamical counterfactuals (Chapter 16): alternative trajectories under shared process noise
Observable counterfactuals (Chapter 25): prediction targets under estimated mechanisms
Twin-network / SWIG diagrams appear again in identification and design chapters when potential outcomes must be drawn explicitly (Richardson and Robins 2013)
10.8 Summary
Structural counterfactuals are interventional queries conditioned on a recovered exogenous realisation. Decompose them as abduction (infer \(\mathbf{u}\)), action (modular \(do(\cdot)\) surgery), and prediction (shared-\(\mathbf{u}\) simulation). compute_counterfactual automates action and prediction once abduction is done; graphs that leave essential noise latent force bounds or sensitivity instead of point answers.
10.9 Further Reading
Pearl (2009): Causality, Chapter 7 (abduction–action–prediction)
Imbens and Rubin (2015): Causal Inference (potential outcomes and identification)
Richardson and Robins (2013): Single-world intervention graphs
Imbens, Guido W., and Donald B. Rubin. 2015. Causal Inference in Statistics, Social, and Biomedical Sciences. Cambridge University Press.
Pearl, Judea. 2009. Causality: Models, Reasoning, and Inference. 2nd ed. Cambridge University Press.
Richardson, Thomas S., and James M. Robins. 2013. “Single World Intervention Graphs (SWIGs): A Unification of the Counterfactual and Graphical Approaches to Causality.”Center for the Statistics and the Social Sciences, University of Washington Series, no. 128.