Math for Causal Inference

Day 55. The Rules of do-Calculus

Three rules, each licensed by a d-separation in a modified graph, let you add or remove observations, swap actions for observations, and add or remove actions. Every identifiable causal effect can be derived with them.

Video coming soon
Learning outcomes
  • ●Build the modified graphs G with incoming or outgoing arrows removed.
  • ●State the three rules of do-calculus and check their graphical conditions.
  • ●Derive the back-door and front-door formulas, and the g-formula for two sequential treatments, step by step.
  • ●Recognise when no sequence of rules can work and show non-identification with two models.
2-HOUR SESSION PLAN
Theory 25′Warm-up (1–5) 20′Proofs (6–10) 35′Applied (11–15) 25′Python & Lab 15′
Colab notebook (.ipynb) Jump to the simulator

Theory

Modified graphs

For sets of nodes X,Z\mathbf X, \mathbf Z in GG:

  • GX‾G_{\overline{\mathbf X}}: delete all arrows into X\mathbf X (the graph after intervening on X\mathbf X);
  • GZ‾G_{\underline{\mathbf Z}}: delete all arrows out of Z\mathbf Z (only back-door paths from Z\mathbf Z remain);
  • GX‾Z‾G_{\overline{\mathbf X}\underline{\mathbf Z}}: both.

The three rules

For disjoint sets X,Y,Z,W\mathbf X, \mathbf Y, \mathbf Z, \mathbf W:

Rule 1 (insert or delete observations).

P(y∣do⁡(x),z,w)=P(y∣do⁡(x),w)if (Y⊥ ⁣ ⁣ ⁣⊥Z∣X,W)GX‾.P(\mathbf y \mid \operatorname{do}(\mathbf x), \mathbf z, \mathbf w) = P(\mathbf y \mid \operatorname{do}(\mathbf x), \mathbf w) \quad \text{if } (\mathbf Y \perp\!\!\!\perp \mathbf Z \mid \mathbf X, \mathbf W)_{G_{\overline{\mathbf X}}}.

Rule 2 (exchange action and observation).

P(y∣do⁡(x),do⁡(z),w)=P(y∣do⁡(x),z,w)if (Y⊥ ⁣ ⁣ ⁣⊥Z∣X,W)GX‾Z‾.P(\mathbf y \mid \operatorname{do}(\mathbf x), \operatorname{do}(\mathbf z), \mathbf w) = P(\mathbf y \mid \operatorname{do}(\mathbf x), \mathbf z, \mathbf w) \quad \text{if } (\mathbf Y \perp\!\!\!\perp \mathbf Z \mid \mathbf X, \mathbf W)_{G_{\overline{\mathbf X}\underline{\mathbf Z}}}.

Rule 3 (insert or delete actions).

P(y∣do⁡(x),do⁡(z),w)=P(y∣do⁡(x),w)if (Y⊥ ⁣ ⁣ ⁣⊥Z∣X,W)GX‾Z(W)‾,P(\mathbf y \mid \operatorname{do}(\mathbf x), \operatorname{do}(\mathbf z), \mathbf w) = P(\mathbf y \mid \operatorname{do}(\mathbf x), \mathbf w) \quad \text{if } (\mathbf Y \perp\!\!\!\perp \mathbf Z \mid \mathbf X, \mathbf W)_{G_{\overline{\mathbf X}\overline{\mathbf Z(\mathbf W)}}},

where Z(W)\mathbf Z(\mathbf W) is the set of Z\mathbf Z-nodes that are not ancestors of any W\mathbf W-node in GX‾G_{\overline{\mathbf X}}.

Reading the rules

  • Rule 1 is d-separation applied in the post-intervention world.
  • Rule 2 says: if Z\mathbf Z has no open back-door paths to Y\mathbf Y (given X,W\mathbf X, \mathbf W), seeing z\mathbf z is as good as setting it. It generalises the back-door criterion.
  • Rule 3 says: if Z\mathbf Z cannot reach Y\mathbf Y through any causal path (given the rest), setting it changes nothing. The Z(W)\mathbf Z(\mathbf W) subtlety handles conditioning on descendants of Z\mathbf Z.

Identification as derivation

A causal query P(y∣do⁡(x))P(\mathbf y \mid \operatorname{do}(\mathbf x)) is identified if the rules, plus ordinary probability, transform it into an expression with no do⁡\operatorname{do}. The rules are complete: if no derivation exists, the effect is not identified from observational data in that graph (Shpitser & Pearl, 2006). Day 56 gives an algorithm that finds the derivation automatically.

Standard moves

  1. Condition and sum: P(y∣do⁡(x))=∑zP(y∣do⁡(x),z)P(z∣do⁡(x))P(y \mid \operatorname{do}(x)) = \sum_z P(y \mid \operatorname{do}(x), z)P(z \mid \operatorname{do}(x)).
  2. Remove the do⁡\operatorname{do} from P(z∣do⁡(x))P(z \mid \operatorname{do}(x)) with Rule 3 (if ZZ is not a descendant) or Rule 2.
  3. Turn do⁡(x)\operatorname{do}(x) into xx inside P(y∣do⁡(x),z)P(y \mid \operatorname{do}(x), z) with Rule 2.

Part 1 · Warm-up

Exercises 1 and 4 use GG: Z→X→YZ \to X \to Y, Z→YZ \to Y, X→WX \to W.

Exercise 1 · Modified graphs

Write the edges of GX‾G_{\overline X}, GX‾G_{\underline X} and GZ‾G_{\overline Z}.

Show solution

Step 1. GX‾G_{\overline X}: remove Z→XZ \to X. Left: X→YX \to Y, Z→YZ \to Y, X→WX \to W.

Step 2. GX‾G_{\underline X}: remove X→YX \to Y, X→WX \to W. Left: Z→XZ \to X, Z→YZ \to Y.

Step 3. GZ‾G_{\overline Z}: ZZ has no incoming arrows, so GZ‾=GG_{\overline Z} = G.

Exercise 2 · Randomised treatment

In X→YX \to Y with XX randomised (no parents), use Rule 2 to show P(y∣do⁡(x))=P(y∣x)P(y \mid \operatorname{do}(x)) = P(y \mid x).

Show solution

Step 1. Rule 2 with empty outer X\mathbf X and W\mathbf W, and Z={X}\mathbf Z = \{X\}: condition (Y⊥ ⁣ ⁣ ⁣⊥X)GX‾(Y \perp\!\!\!\perp X)_{G_{\underline X}}.

Step 2. GX‾G_{\underline X} removes X→YX \to Y: no edges remain, so XX and YY are d-separated.

Answer: Rule 2 applies: P(y∣do⁡(x))=P(y∣x)P(y \mid \operatorname{do}(x)) = P(y \mid x).

Exercise 3 · Actions that cannot matter

If XX is not an ancestor of YY, show P(y∣do⁡(x))=P(y)P(y \mid \operatorname{do}(x)) = P(y) with Rule 3.

Show solution

Step 1. Rule 3 with empty W\mathbf W: condition (Y⊥ ⁣ ⁣ ⁣⊥X)GX‾(Y \perp\!\!\!\perp X)_{G_{\overline X}}.

Step 2. In GX‾G_{\overline X}, XX has no incoming arrows; any path from XX starts X→⋯X \to \cdots.

Step 3. Since XX is not an ancestor of YY, such a path must contain a collider (it cannot be directed all the way to YY); unconditioned, it is blocked.

Answer: d-separated, so P(y∣do⁡(x))=P(y)P(y \mid \operatorname{do}(x)) = P(y).

Exercise 4 · Rule 1 in action

In GG, is P(y∣do⁡(x),w)=P(y∣do⁡(x))P(y \mid \operatorname{do}(x), w) = P(y \mid \operatorname{do}(x))?

Show solution

Step 1. Rule 1 condition: (Y⊥ ⁣ ⁣ ⁣⊥W∣X)GX‾(Y \perp\!\!\!\perp W \mid X)_{G_{\overline X}}.

Step 2. In GX‾G_{\overline X}, paths YY–WW: Y←X→WY \leftarrow X \to W (fork at XX, conditioned: blocked).

Step 3. Y←Z→YY \leftarrow Z \to Y is not a path to WW; and Z→XZ \to X is gone, so no other path exists.

Answer: yes; once XX is set, WW (a side effect of XX) carries no information about YY.

Exercise 5 · Name the rule

Which rule justifies each step? (a) P(z∣do⁡(x))=P(z)P(z \mid \operatorname{do}(x)) = P(z) for a pre-treatment ZZ. (b) P(y∣do⁡(x),z)=P(y∣x,z)P(y \mid \operatorname{do}(x), z) = P(y \mid x, z) when ZZ blocks the back-door paths. (c) Dropping a measured side effect of treatment from the conditioning set.

Show solution

Step 1. (a) Rule 3 (deleting an action that cannot affect ZZ).

Step 2. (b) Rule 2 (exchanging the action do⁡(x)\operatorname{do}(x) for the observation xx).

Step 3. (c) Rule 1 (deleting an observation).

Part 2 · Proofs

Exercise 6 · The back-door formula by do-calculus

Let Z\mathbf Z satisfy the back-door criterion for (X,Y)(X, Y). Derive P(y∣do⁡(x))=∑zP(y∣x,z)P(z)P(y \mid \operatorname{do}(x)) = \sum_{\mathbf z} P(y \mid x, \mathbf z)P(\mathbf z).

Show solution

Step 1. Condition and sum: P(y∣do⁡(x))=∑zP(y∣do⁡(x),z)P(z∣do⁡(x))P(y \mid \operatorname{do}(x)) = \sum_{\mathbf z} P(y \mid \operatorname{do}(x), \mathbf z)P(\mathbf z \mid \operatorname{do}(x)).

Step 2. Rule 3 for P(z∣do⁡(x))P(\mathbf z \mid \operatorname{do}(x)): need (Z⊥ ⁣ ⁣ ⁣⊥X)GX‾(\mathbf Z \perp\!\!\!\perp X)_{G_{\overline X}}. In GX‾G_{\overline X}, paths from XX leave through its children; since no Z\mathbf Z node is a descendant of XX, each such path meets a collider and is blocked. So P(z∣do⁡(x))=P(z)P(\mathbf z \mid \operatorname{do}(x)) = P(\mathbf z).

Step 3. Rule 2 for P(y∣do⁡(x),z)P(y \mid \operatorname{do}(x), \mathbf z): need (Y⊥ ⁣ ⁣ ⁣⊥X∣Z)GX‾(Y \perp\!\!\!\perp X \mid \mathbf Z)_{G_{\underline X}}. In GX‾G_{\underline X} only back-door paths from XX remain, and Z\mathbf Z blocks them all. So P(y∣do⁡(x),z)=P(y∣x,z)P(y \mid \operatorname{do}(x), \mathbf z) = P(y \mid x, \mathbf z).

Step 4. Substitute. ■\blacksquare (This also proves fact (b) assumed on Day 52.)

Exercise 7 · Front door, first piece

In the front-door graph U→XU \to X, U→YU \to Y, X→M→YX \to M \to Y (UU unobserved), show P(m∣do⁡(x))=P(m∣x)P(m \mid \operatorname{do}(x)) = P(m \mid x).

Show solution

Step 1. Rule 2 condition: (M⊥ ⁣ ⁣ ⁣⊥X)GX‾(M \perp\!\!\!\perp X)_{G_{\underline X}}.

Step 2. GX‾G_{\underline X} removes X→MX \to M. Remaining paths XX–MM: X←U→Y←MX \leftarrow U \to Y \leftarrow M, with a collider at YY: blocked.

Answer: Rule 2 applies. ■\blacksquare

Exercise 8 · Front door, second piece

In the same graph, show P(y∣do⁡(m))=∑xP(y∣m,x)P(x)P(y \mid \operatorname{do}(m)) = \sum_x P(y \mid m, x)P(x).

Show solution

Step 1. Condition and sum: P(y∣do⁡(m))=∑xP(y∣do⁡(m),x)P(x∣do⁡(m))P(y \mid \operatorname{do}(m)) = \sum_x P(y \mid \operatorname{do}(m), x)P(x \mid \operatorname{do}(m)).

Step 2. Rule 2 on the first factor: (Y⊥ ⁣ ⁣ ⁣⊥M∣X)GM‾(Y \perp\!\!\!\perp M \mid X)_{G_{\underline M}}. Removing M→YM \to Y leaves the path M←X←U→YM \leftarrow X \leftarrow U \to Y, blocked by XX (chain). So P(y∣do⁡(m),x)=P(y∣m,x)P(y \mid \operatorname{do}(m), x) = P(y \mid m, x).

Step 3. Rule 3 on the second factor: (X⊥ ⁣ ⁣ ⁣⊥M)GM‾(X \perp\!\!\!\perp M)_{G_{\overline M}}. Removing X→MX \to M leaves M→Y←U→XM \to Y \leftarrow U \to X with a collider at YY: blocked. So P(x∣do⁡(m))=P(x)P(x \mid \operatorname{do}(m)) = P(x).

Step 4. Substitute. ■\blacksquare

Exercise 9 · Front door, assembled

Complete the derivation of P(y∣do⁡(x))=∑mP(m∣x)∑x′P(y∣m,x′)P(x′)P(y \mid \operatorname{do}(x)) = \sum_m P(m \mid x)\sum_{x'} P(y \mid m, x')P(x').

Show solution

Step 1. Condition and sum: P(y∣do⁡(x))=∑mP(y∣do⁡(x),m)P(m∣do⁡(x))P(y \mid \operatorname{do}(x)) = \sum_m P(y \mid \operatorname{do}(x), m)P(m \mid \operatorname{do}(x)).

Step 2. The second factor is P(m∣x)P(m \mid x) (Exercise 7).

Step 3. Rule 2 on the first: (Y⊥ ⁣ ⁣ ⁣⊥M∣X)GX‾M‾(Y \perp\!\!\!\perp M \mid X)_{G_{\overline X}\underline M}. Removing arrows into XX and out of MM leaves no path MM–YY except through XX, which is conditioned. So P(y∣do⁡(x),m)=P(y∣do⁡(x),do⁡(m))P(y \mid \operatorname{do}(x), m) = P(y \mid \operatorname{do}(x), \operatorname{do}(m)).

Step 4. Rule 3: (Y⊥ ⁣ ⁣ ⁣⊥X∣M)GX‾ M‾(Y \perp\!\!\!\perp X \mid M)_{G_{\overline X\,\overline M}}. With arrows into XX and MM removed, XX is isolated. So P(y∣do⁡(x),do⁡(m))=P(y∣do⁡(m))P(y \mid \operatorname{do}(x), \operatorname{do}(m)) = P(y \mid \operatorname{do}(m)).

Step 5. By Exercise 8, P(y∣do⁡(m))=∑x′P(y∣m,x′)P(x′)P(y \mid \operatorname{do}(m)) = \sum_{x'} P(y \mid m, x')P(x'). Substitute. ■\blacksquare

Exercise 10 · Two models, one distribution

In the "bow" graph X→YX \to Y with X↔YX \leftrightarrow Y, show that P(y∣do⁡(x))P(y \mid \operatorname{do}(x)) is not identified by exhibiting two SCMs with the same P(x,y)P(x, y) and different interventional distributions.

Show solution

Step 1. Model A: U∼Bernoulli(0.5)U \sim \text{Bernoulli}(0.5), X:=UX := U, Y:=UY := U. XX has no effect on YY.

Step 2. Model B: X:=U∼Bernoulli(0.5)X := U \sim \text{Bernoulli}(0.5), Y:=XY := X. Effect of 1.

Step 3. Both give P(X=Y=1)=P(X=Y=0)=0.5P(X = Y = 1) = P(X = Y = 0) = 0.5: identical observational distributions.

Step 4. P(Y=1∣do⁡(X=1))P(Y = 1 \mid \operatorname{do}(X = 1)) is 0.5 in Model A and 1 in Model B.

Answer: data cannot distinguish the models, so no formula can recover the effect: it is not identified. ■\blacksquare

Part 3 · Applied

Exercise 11 · A tax credit and labour supply

An earned-income tax credit XX (eligibility depends on number of children CC) affects hours worked YY; children also affect hours directly. Graph: C→XC \to X, C→YC \to Y, X→YX \to Y. Derive P(y∣do⁡(x))P(y \mid \operatorname{do}(x)) with the rules, naming each.

Show solution

Step 1. Condition and sum: P(y∣do⁡(x))=∑cP(y∣do⁡(x),c)P(c∣do⁡(x))P(y \mid \operatorname{do}(x)) = \sum_c P(y \mid \operatorname{do}(x), c)P(c \mid \operatorname{do}(x)).

Step 2. Rule 3: in GX‾G_{\overline X} the arrow C→XC \to X is gone; paths XX–CC: X→Y←CX \to Y \leftarrow C, collider: blocked. So P(c∣do⁡(x))=P(c)P(c \mid \operatorname{do}(x)) = P(c).

Step 3. Rule 2: in GX‾G_{\underline X}, paths XX–YY: X←C→YX \leftarrow C \to Y, blocked by CC. So P(y∣do⁡(x),c)=P(y∣x,c)P(y \mid \operatorname{do}(x), c) = P(y \mid x, c).

Answer: P(y∣do⁡(x))=∑cP(y∣x,c)P(c)P(y \mid \operatorname{do}(x)) = \sum_c P(y \mid x, c)P(c): compare hours of eligible and ineligible families with the same number of children, and average over the distribution of family size.

Exercise 12 · Effects within subgroups

In Exercise 11's graph plus a pre-treatment region indicator RR (R→CR \to C, R→YR \to Y), derive the region-specific effect P(y∣do⁡(x),r)P(y \mid \operatorname{do}(x), r).

Show solution

Step 1. Condition and sum within region: P(y∣do⁡(x),r)=∑cP(y∣do⁡(x),c,r)P(c∣do⁡(x),r)P(y \mid \operatorname{do}(x), r) = \sum_c P(y \mid \operatorname{do}(x), c, r)P(c \mid \operatorname{do}(x), r).

Step 2. Rule 3 (with W={R}\mathbf W = \{R\}): in GX‾G_{\overline X}, paths XX–CC go through the collider YY (X→Y←CX \to Y \leftarrow C or X→Y←R→CX \to Y \leftarrow R \to C), unconditioned: blocked. So P(c∣do⁡(x),r)=P(c∣r)P(c \mid \operatorname{do}(x), r) = P(c \mid r).

Step 3. Rule 2: in GX‾G_{\underline X}, back-door paths X←C→YX \leftarrow C \to Y and X←C←R→YX \leftarrow C \leftarrow R \to Y are blocked by CC. So P(y∣do⁡(x),c,r)=P(y∣x,c,r)P(y \mid \operatorname{do}(x), c, r) = P(y \mid x, c, r).

Answer: P(y∣do⁡(x),r)=∑cP(y∣x,c,r)P(c∣r)P(y \mid \operatorname{do}(x), r) = \sum_c P(y \mid x, c, r)P(c \mid r), a conditional (CATE-type) version of the adjustment formula.

Exercise 13 · Two rounds of HIV treatment

A clinic decides treatment X1X_1 at the first visit; CD4 count LL is measured; treatment X2X_2 is decided at the second visit based on LL; viral suppression YY is measured. Graph: X1→LX_1 \to L, X1→YX_1 \to Y, L→X2L \to X_2, X2→YX_2 \to Y, U→LU \to L, U→YU \to Y (UU = unobserved health status); X1X_1 is randomised. Derive P(y∣do⁡(x1),do⁡(x2))P(y \mid \operatorname{do}(x_1), \operatorname{do}(x_2)).

Show solution

Step 1. Condition on LL and sum: P(y∣do⁡(x1,x2))=∑lP(y∣do⁡(x1,x2),l) P(l∣do⁡(x1,x2))P(y \mid \operatorname{do}(x_1, x_2)) = \sum_l P(y \mid \operatorname{do}(x_1, x_2), l)\,P(l \mid \operatorname{do}(x_1, x_2)).

Step 2. Rule 3 removes do⁡(x2)\operatorname{do}(x_2) from the second factor: X2X_2 is not an ancestor of LL. Then Rule 2 turns do⁡(x1)\operatorname{do}(x_1) into x1x_1: X1X_1 has no back-door paths. So P(l∣do⁡(x1,x2))=P(l∣x1)P(l \mid \operatorname{do}(x_1, x_2)) = P(l \mid x_1).

Step 3. Rule 2 for X2X_2 in the first factor: in GX1‾X2‾G_{\overline{X_1}\underline{X_2}}, back-door paths from X2X_2 (X2←L←U→YX_2 \leftarrow L \leftarrow U \to Y, X2←L←X1→YX_2 \leftarrow L \leftarrow X_1 \to Y) are blocked by LL (and X1X_1). So it equals P(y∣do⁡(x1),x2,l)P(y \mid \operatorname{do}(x_1), x_2, l).

Step 4. Rule 2 for X1X_1: in GX1‾G_{\underline{X_1}}, X1X_1 has no remaining edges. So it equals P(y∣x1,x2,l)P(y \mid x_1, x_2, l).

Answer: the g-formula P(y∣do⁡(x1,x2))=∑lP(y∣x1,l,x2) P(l∣x1)P(y \mid \operatorname{do}(x_1, x_2)) = \sum_l P(y \mid x_1, l, x_2)\,P(l \mid x_1). Note that regressing YY on X1,X2,LX_1, X_2, L would be wrong: LL is a mediator for X1X_1 and a collider (X1→L←UX_1 \to L \leftarrow U). Day 96 develops this.

Exercise 14 · Ice cream and drowning

Hot weather HH raises ice-cream sales II and swimming, hence drownings DD: H→IH \to I, H→DH \to D. A mayor proposes banning ice cream to cut drownings. Use Rule 3 to evaluate the proposal, and contrast with the observational association.

Show solution

Step 1. Rule 3: (D⊥ ⁣ ⁣ ⁣⊥I)GI‾(D \perp\!\!\!\perp I)_{G_{\overline I}}? Removing H→IH \to I isolates II: d-separated.

Step 2. So P(d∣do⁡(i))=P(d)P(d \mid \operatorname{do}(i)) = P(d): setting ice-cream sales to zero changes nothing.

Step 3. Observationally, P(d∣i)P(d \mid i) rises with ii through the fork I←H→DI \leftarrow H \to D.

Answer: the ban would not reduce drownings; the association is pure confounding by weather.

Exercise 15 · A non-identified effect, numerically

A health economist has data only on insurance status XX and medical spending YY (both binary), with unobserved health UU affecting both. Build two SCMs matching P(X=1,Y=1)=0.3P(X = 1, Y = 1) = 0.3, P(X=1,Y=0)=0.2P(X = 1, Y = 0) = 0.2, P(X=0,Y=1)=0.1P(X = 0, Y = 1) = 0.1, P(X=0,Y=0)=0.4P(X = 0, Y = 0) = 0.4, one where insurance has no effect and one where it does.

Show solution

Step 1. Model A (no effect): let UU take four values that encode (X,Y)(X, Y) directly, with P(U=(x,y))P(U = (x, y)) equal to the table; set X:=U1X := U_1, Y:=U2Y := U_2. The table is reproduced and YY does not depend on XX: P(Y=1∣do⁡(x))=P(Y=1)=0.4P(Y = 1 \mid \operatorname{do}(x)) = P(Y = 1) = 0.4 for both xx.

Step 2. Model B (no confounding): X∼Bernoulli(0.5)X \sim \text{Bernoulli}(0.5) and Y:=1[V<pX]Y := \mathbf 1[V < p_X] with VV uniform, p1=0.3/0.5=0.6p_1 = 0.3/0.5 = 0.6, p0=0.1/0.5=0.2p_0 = 0.1/0.5 = 0.2. Same table; causal effect 0.6−0.2=0.40.6 - 0.2 = 0.4.

Answer: both models fit the data perfectly; the effect could be 0 or 0.4. Without an admissible set, a front door or an instrument, the data are silent.

Verify in Python

import networkx as nx

dsep = getattr(nx, "is_d_separator", None) or nx.d_separated   # name changed in networkx 3.3

def cut(G, into=(), out_of=()):
    """Remove arrows into the nodes in `into` and out of the nodes in `out_of`."""
    H = G.copy()
    H.remove_edges_from([e for e in G.edges if e[1] in into or e[0] in out_of])
    return H

# Front-door graph (U explicit)
F = nx.DiGraph([("U", "X"), ("U", "Y"), ("X", "M"), ("M", "Y")])
print("Ex 7  rule 2:", dsep(cut(F, out_of={"X"}), {"M"}, {"X"}, set()))
print("Ex 8  rule 2:", dsep(cut(F, out_of={"M"}), {"Y"}, {"M"}, {"X"}), " rule 3:", dsep(cut(F, into={"M"}), {"X"}, {"M"}, set()))
print("Ex 9  rule 2:", dsep(cut(F, into={"X"}, out_of={"M"}), {"Y"}, {"M"}, {"X"}),
      " rule 3:", dsep(cut(F, into={"X", "M"}), {"Y"}, {"X"}, {"M"}))

# Exercise 13: two rounds of treatment
H = nx.DiGraph([("X1", "L"), ("X1", "Y"), ("L", "X2"), ("X2", "Y"), ("U", "L"), ("U", "Y")])
print("Ex 13 rule 3 (X2 on L):", dsep(cut(H, into={"X2"}), {"L"}, {"X2"}, set()),
      " rule 2 (X1 on L):", dsep(cut(H, out_of={"X1"}), {"L"}, {"X1"}, set()))
print("      rule 2 (X2 on Y):", dsep(cut(H, into={"X1"}, out_of={"X2"}), {"Y"}, {"X2"}, {"X1", "L"}),
      " rule 2 (X1 on Y):", dsep(cut(H, out_of={"X1"}), {"Y"}, {"X1"}, {"X2", "L"}))
print("      naive regression on L is invalid for X1: L is a descendant of X1:", "L" in nx.descendants(H, "X1"))

# Exercise 15: two SCMs, same data, different effects
table = {(1, 1): .3, (1, 0): .2, (0, 1): .1, (0, 0): .4}
modelA = {x: sum(v for (xx, y), v in table.items() if y == 1) for x in (0, 1)}            # Y ignores X
pX = {x: sum(v for (xx, y), v in table.items() if xx == x) for x in (0, 1)}
modelB = {x: table[x, 1] / pX[x] for x in (0, 1)}
print("P(Y=1|do(x)) model A:", modelA, " model B:", {k: round(v, 2) for k, v in modelB.items()})

Key takeaways

  • Rule 1 adds or removes observations, Rule 2 swaps actions and observations, Rule 3 adds or removes actions; each needs a d-separation in a modified graph.
  • The back-door and front-door formulas, and the g-formula for sequential treatments, are short derivations.
  • The rules are complete: if no derivation exists, two models with the same data but different effects can be built.

Simulation Lab: do-Calculus, Step by Step

Open full screen →

Walk through the back-door, front-door and g-formula derivations with each rule's d-separation checked in its modified graph.

G with arrows out of X removed
UXMY
Rule 2: is (M ⫫ X) in this graph? Yes ✓

Step through a derivation. For each step that uses a rule, the panel builds the modified graph the rule requires and checks the d-separation live. Conditioned nodes are grey; the two sets that must be separated are blue and green; U is unobserved.

Day 54Day 56