Day 49. d-Separation
One rule for reading every conditional independence a DAG implies. A path is blocked by a conditioning set if it has a chain or fork whose middle is conditioned on, or a collider that is not; two sets are d-separated if every path between them is blocked.
- ●Decide whether a path is open or blocked given a conditioning set.
- ●Decide whether two variables are d-separated by enumerating paths.
- ●Prove the Markov blanket property and that the local Markov property is a special case of d-separation.
- ●Use d-separation to compare candidate DAGs, check instruments and reason about missing data.
Theory
Blocking a path
Let be a set of conditioned variables. A path between and is blocked by if it contains at least one node such that
- is the middle of a chain () or fork () and , or
- is a collider () and neither nor any descendant of is in .
A path that is not blocked is open (or active). Open paths carry association.
d-separation
and are d-separated by , written , if every path between them is blocked by . Otherwise they are d-connected.
The global Markov property
If factorises according to (Day 47), then
d-separation is sound (it never claims a false independence) and, under faithfulness, complete (every independence in is a d-separation). The local Markov property is the special case "parents separate a node from its other non-descendants".
Recipe
- List every path between and (ignoring arrow directions, no repeated nodes).
- For each path, classify each interior node as chain, fork or collider.
- The path is open only if every chain/fork middle is outside and every collider is in or has a descendant in .
- and are d-separated if no path is open.
Software does this efficiently (the "Bayes-ball" algorithm, or networkx.is_d_separator). The lab lets you click a conditioning set and watch paths open and close.
Non-monotonicity
Adding a variable to can open a path (if it is a collider or a collider's descendant) as well as close one. "Control for more" is not automatically safer.
Markov blanket
The Markov blanket of is its parents, children and the other parents of its children. Given its blanket, is d-separated from every other variable: the blanket is the smallest set worth knowing to predict .
Part 1 · Warm-up
Exercises 1–5 use this DAG: , , , , , , .
Exercise 1 · List the paths
List every path between and and classify the interior nodes.
Show solution
Step 1. : is a chain middle.
Step 2. : is a fork, a chain middle.
Step 3. : is a collider.
Answer: three paths.
Exercise 2 · Nothing conditioned
Are and d-separated by the empty set?
Show solution
Step 1. Path 1: chain through , not conditioned: open.
Step 2. One open path suffices.
Answer: no, they are d-connected. (Path 2 is also open; path 3 is blocked by the unconditioned collider.)
Exercise 3 · Conditioning on and
Are and d-separated by ?
Show solution
Step 1. Path 1: conditioned, chain: blocked.
Step 2. Path 2: conditioned, chain: blocked.
Step 3. Path 3: collider not conditioned and has no descendants: blocked.
Answer: yes, d-separated.
Exercise 4 · Adding
Are and d-separated by ?
Show solution
Step 1. Paths 1 and 2 stay blocked.
Step 2. Path 3: the collider is now conditioned: open.
Answer: no. Adding re-connects and (non-monotonicity).
Exercise 5 · A different pair
Is d-separated from by ?
Show solution
Step 1. : chain at , conditioned: blocked.
Step 2. : collider ; neither nor its descendant is conditioned: blocked.
Step 3. : collider not conditioned: blocked (also is a fork middle, conditioned).
Step 4. : is a chain middle, conditioned: blocked.
Answer: yes, every path is blocked.
Part 2 · Proofs
Exercise 6 · Neighbours are never separated
Prove that if is an edge, no set (excluding ) d-separates them.
Show solution
Step 1. The one-edge path has no interior nodes.
Step 2. Blocking requires an interior node satisfying condition 1 or 2; there is none.
Step 3. So this path is open for every , and are d-connected.
This is why missing arrows, not present ones, carry the testable content of a DAG.
Exercise 7 · Local Markov from d-separation
Prove that every node is d-separated from any non-descendant (not a parent) by .
Show solution
Step 1. Take any path from to . Case A: it starts with an edge into , , so is a parent.
Step 2. At the path continues either (chain) or (fork). cannot be a collider, because the edge points out of it. is conditioned, so the path is blocked.
Step 3. Case B: the path starts . Follow it while the arrows keep pointing forward: . All these nodes are descendants of .
Step 4. is not a descendant, so the arrows must reverse somewhere: there is a collider with , and is a descendant of .
Step 5. Neither nor its descendants can be parents of (that would create a cycle). So the collider is unconditioned with no conditioned descendant: blocked.
Exercise 8 · The Markov blanket
Prove that is d-separated from every node outside its Markov blanket (parents, children, children's other parents) given .
Show solution
Step 1. Paths leaving through a parent : as in Exercise 7, is a conditioned chain or fork middle: blocked.
Step 2. Paths leaving through a child and continuing : is a conditioned chain middle: blocked.
Step 3. Paths continuing : is a conditioned collider, so open at ; but then is a co-parent, in .
Step 4. At the path continues or (not a collider, since points out). is conditioned: blocked.
Step 5. Every path is blocked.
Exercise 9 · No common ancestor, no association
Prove that if and have no common ancestor (counting each node as its own ancestor), they are d-separated by the empty set.
Show solution
Step 1. With , a path is open only if it has no colliders.
Step 2. A collider-free path has at most one node where the arrows point away on both sides, otherwise there would be a collider between two such nodes. Call that node (possibly an endpoint).
Step 3. From , both halves of the path are directed paths towards and towards , so is a common ancestor.
Step 4. There is none, so no path is open, and are d-separated. (Reichenbach's principle: dependence requires a causal link or a common cause, absent selection.)
Exercise 10 · More control can hurt
Give a three-node DAG in which is implied but is not, and one in which the reverse holds.
Show solution
Step 1. Collider : the only path is blocked given and open given .
Step 2. Chain (or fork ): the only path is open given and blocked given .
Answer: d-separation is not monotone in the conditioning set; which variables to condition on depends on the graph, not on "more is better".
Part 3 · Applied
Exercise 11 · Two stories about microcredit
DAG 1: education loan income . DAG 2: , , . Which testable independence separates them? In survey data, the regression of income on loans and education gives a large, precise education coefficient. Which DAG survives?
Show solution
Step 1. DAG 1 implies (chain blocked at ).
Step 2. DAG 2 has the edge , so by Exercise 6 no independence between and is implied.
Step 3. In a linear model, means a zero education coefficient once loans are included.
Answer: a large, precise coefficient rejects DAG 1; DAG 2 survives (education affects income other than through loans).
Exercise 12 · Pollution, allergies and the emergency room
Air pollution asthma attack allergy , and emergency visit . Pollution and allergy have no common cause. Is implied? Is ? What does this mean for a study using only emergency-room records?
Show solution
Step 1. One path: , a collider at .
Step 2. Given nothing: blocked, so .
Step 3. Given : is a descendant of the collider, so the path opens: not d-separated.
Answer: among ER patients, pollution and allergies will look negatively related (an attack on a clean-air day is more likely to be allergic). ER-only data condition on a collider's descendant.
Exercise 13 · School meals
A DAG for a school-meals programme: household income meals , attendance , nutrition test score , , rainfall . Decide: (a) ? (b) ? (c) ?
Show solution
Step 1. (a) Paths –: (collider ) and (collider ). Both blocked: yes.
Step 2. (b) Conditioning on opens the collider in the second path: is open. Also is a descendant of , opening the first path. Not d-separated.
Step 3. (c) Paths –: (blocked by ) and (blocked by , a fork). Yes.
Answer: yes, no, yes. Statement (c) is testable: given nutrition and income, meals should not predict test scores.
Exercise 14 · Checking an instrument
The Vietnam draft lottery affects military service , which affects later earnings ; unobserved motivation affects both and . (a) Is implied? (b) Is implied? (c) Why is "regress earnings on the lottery, controlling for service" a mistake?
Show solution
Step 1. (a) Path has a collider at : blocked. Yes, (the lottery is random).
Step 2. (b) Paths –: (blocked by ) and (collider conditioned: open). Not d-separated.
Step 3. (c) Conditioning on service opens , so the "direct effect" of the lottery picks up motivation differences: among veterans, those with losing lottery numbers volunteered.
Answer: use the lottery as an instrument (Phase 5), not as a control alongside service.
Exercise 15 · When is survey non-response ignorable?
In a household survey, income is missing when the response indicator . Covariates (region, household size) are always observed. Draw two DAGs, one where depends only on and one where it also depends on , and state the d-separation that makes complete-case analysis within valid.
Show solution
Step 1. DAG A: , . Paths –: , blocked by . So : missing at random (Day 14).
Step 2. DAG B: add (rich households refuse). Now and are adjacent; no set separates them.
Step 3. Under DAG A, , so complete cases within each cell (or weighting by ) recover the income distribution.
Answer: the condition is ; under DAG B it fails (missing not at random) and only bounds or extra assumptions help.
Verify in Python
import networkx as nx
dsep = getattr(nx, "is_d_separator", None) or nx.d_separated # name changed in networkx 3.3
G = nx.DiGraph([("Z", "X"), ("Z", "W"), ("W", "Y"), ("X", "M"), ("M", "Y"), ("X", "C"), ("Y", "C")])
print("paths X-Y:", list(nx.all_simple_paths(G.to_undirected(), "X", "Y")))
for Zs in [set(), {"M", "W"}, {"M", "W", "C"}]:
print(f"X _||_ Y | {sorted(Zs)}:", dsep(G, {"X"}, {"Y"}, Zs))
print("Z _||_ M | X:", dsep(G, {"Z"}, {"M"}, {"X"}))
# Exercise 13: school meals
S = nx.DiGraph([("I", "M"), ("I", "A"), ("M", "N"), ("N", "T"), ("A", "T"), ("R", "A")])
print("M _||_ R:", dsep(S, {"M"}, {"R"}, set()), "| M _||_ R | T:", dsep(S, {"M"}, {"R"}, {"T"}),
"| M _||_ T | N,I:", dsep(S, {"M"}, {"T"}, {"N", "I"}))
# Exercise 14: draft lottery
L = nx.DiGraph([("Z", "D"), ("D", "Y"), ("U", "D"), ("U", "Y")])
print("Z _||_ U:", dsep(L, {"Z"}, {"U"}, set()), "| Z _||_ Y | D:", dsep(L, {"Z"}, {"Y"}, {"D"}))
# All pairwise marginal independences implied by the school-meals DAG
nodes = sorted(S)
print("marginally independent pairs:", [(a, b) for i, a in enumerate(nodes) for b in nodes[i + 1:] if dsep(S, {a}, {b}, set())])
Key takeaways
- A path is blocked by a conditioned chain or fork middle, or by an unconditioned collider with no conditioned descendants.
- d-separation (all paths blocked) implies conditional independence in every distribution that factorises over the DAG.
- Conditioning can open paths as well as close them; the graph, not intuition, decides what to control for.
Simulation Lab: d-Separation Explorer
Open full screen →Pick two variables and a conditioning set in a school-meals DAG; every path is listed as open or blocked, with the reason.
Pick the two variables and click nodes to add or remove them from the conditioning set. Every path between the two is listed with its junctions; a path is blocked by a conditioned chain or fork, or by a collider with nothing conditioned at or below it. Open paths are drawn in orange.