Graphical models
Update a prior, compare posterior means with MAP estimates and interpret predictive uncertainty.
THE IDEA
A graph is a factorisation
A joint distribution over many variables is expensive to write down: n yes/no variables need 2^n - 1 numbers. A graphical model uses arrows to say which variables directly depend on which, and the joint becomes a product of small tables. Take Rain (R), Sprinkler (S) and Wet grass (W), where rain and the sprinkler can each wet the grass:
P(R, S, W) = P(R) * P(S) * P(W | R, S)
parameters: 1 + 1 + 4 = 6 numbers instead of 2^3 - 1 = 7
for 20 variables with at most 3 parents each, the product needs at most 20 * 2^3 = 160 numbers; the full table needs 1,048,575The missing arrow between R and S states an assumption: they are independent unless you condition on something they both influence.
Inference by enumeration
To answer "how likely is rain, given wet grass?" list every world (8 here), compute its probability from the product, keep the worlds that agree with the evidence, and divide. Set evidence in the lab and watch which rows light up.
P(Rain) = 0.2, P(Sprinkler) = 0.3, and P(Wet | Rain, Sprinkler) = 0.99 / 0.9 / 0.85 / 0 for (yes,yes) / (yes,no) / (no,yes) / (no,no).
| query | exact P(true | evidence) |
|---|---|
| Rain | 0.4761 |
| Sprinkler on | 0.6764 |
| R | S | W | P(R) P(S) P(W|R,S) | kept |
|---|---|---|---|---|
| 0 | 0 | 0 | 0.56 | no |
| 0 | 0 | 1 | 0 | yes |
| 0 | 1 | 0 | 0.036 | no |
| 0 | 1 | 1 | 0.204 | yes |
| 1 | 0 | 0 | 0.014 | no |
| 1 | 0 | 1 | 0.126 | yes |
| 1 | 1 | 0 | 0.0006 | no |
| 1 | 1 | 1 | 0.0594 | yes |
| sum of kept rows | 0.3894 | |||
Enumeration: keep the 8 worlds that agree with the evidence, add up the weight of the ones where the query is true, and divide by the total weight kept.
Explaining away
Before any observation rain has probability 0.2. If you learn the grass is wet it jumps to 0.4761: wet grass makes rain a likelier explanation. Now learn the sprinkler was on. The grass is already explained, so rain falls back to 0.2255. Rain and the sprinkler were independent, but become dependent once you condition on their common effect. That is the signature of a collider, and it is easy to get wrong by intuition.
Predict first. You see wet grass and learn the sprinkler was off. What happens to P(rain)?
Arrows are not causes
The same joint distribution can be written with the arrows reversed. Below, A to B to C and C to B to A produce identical numbers in all 8 rows, so no amount of observational data can tell you which direction is causal. Arrows in a probabilistic graph encode dependence structure; reading them as causation needs extra assumptions or experiments (intervening on A and watching C).
| A | B | C | arrows A to C | arrows C to A |
|---|---|---|---|---|
| 0 | 0 | 0 | 0.504 | 0.504 |
| 0 | 0 | 1 | 0.056 | 0.056 |
| 0 | 1 | 0 | 0.042 | 0.042 |
| 0 | 1 | 1 | 0.098 | 0.098 |
| 1 | 0 | 0 | 0.054 | 0.054 |
| 1 | 0 | 1 | 0.006 | 0.006 |
| 1 | 1 | 0 | 0.072 | 0.072 |
| 1 | 1 | 1 | 0.168 | 0.168 |
Chapter context
Probabilistic modeling represents uncertainty explicitly instead of presenting every fitted number as certain. Priors, likelihoods and approximation choices are assumptions that should be exposed rather than hidden behind a library call.
TRY IT YOURSELF
Part 1. Do it hands-on
The lab starts with wet grass observed. Tasks are graded from exact enumeration.
P(Rain) = 0.2, P(Sprinkler) = 0.3, and P(Wet | Rain, Sprinkler) = 0.99 / 0.9 / 0.85 / 0 for (yes,yes) / (yes,no) / (no,yes) / (no,no).
| query | exact P(true | evidence) |
|---|---|
| Rain | 0.2 |
| Sprinkler on | 0.3 |
| Grass wet | 0.3894 |
| R | S | W | P(R) P(S) P(W|R,S) | kept |
|---|---|---|---|---|
| 0 | 0 | 0 | 0.56 | yes |
| 0 | 0 | 1 | 0 | yes |
| 0 | 1 | 0 | 0.036 | yes |
| 0 | 1 | 1 | 0.204 | yes |
| 1 | 0 | 0 | 0.014 | yes |
| 1 | 0 | 1 | 0.126 | yes |
| 1 | 1 | 0 | 0.0006 | yes |
| 1 | 1 | 1 | 0.0594 | yes |
| sum of kept rows | 1 | |||
Enumeration: keep the 8 worlds that agree with the evidence, add up the weight of the ones where the query is true, and divide by the total weight kept.
- To do: Leave Rain unknown and set evidence so that P(Rain) is above 0.9
- To do: Explaining away: observe wet grass and the sprinkler on, so that P(Rain) falls below 0.25
- To do: Find evidence on the sprinkler alone (nothing else observed) and confirm P(Rain) stays at its prior 0.2
Part 2. Do it in code
- NET holds the network Rain (R) and Sprinkler (S) -> Wet grass (W). Use the dict as given; each variable is 0 or 1.
- joint_table(net): a numpy array of shape (2, 2, 2) indexed [r][s][w] with the joint probability P(r) P(s) P(w given r, s). It must sum to 1.
- query(var, evidence, net=NET): P(var = 1 given evidence) by enumeration. evidence is a dict such as {"W": 1, "S": 0}. Raise ValueError for an unknown variable name or if the evidence has probability 0.
- explaining_away(net=NET): return the pair (P(R=1 given W=1), P(R=1 given W=1 and S=1)).
Stuck, or something not working? You can come back to it any time.
CHECK YOUR UNDERSTANDING
Does drawing an arrow from A to B prove A causes B?
Chapter reference: math, worked example & code
This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.
Math and notation
For Bernoulli success probability theta and a Beta prior:
For Beta(alpha,beta) with both parameters greater than one, the MAP is .
For a zero-mean Gaussian-process regression model with independent noise variance sigma-n squared, a test prediction has
K is the training covariance matrix, k-star connects the test input with training inputs, and k-star-star is its prior variance. This is latent-function variance; observation noise adds another term for a noisy predicted observation. Practical code solves systems instead of explicitly computing an inverse.
Worked example
Start with Beta(2,2), then observe three successes and one failure. The posterior is Beta(5,3). Its mean is 5/8=0.625. Its MAP is 4/6≈0.6667. Both summarize the same distribution but answer different questions.
Reference code
The following example uses the Python standard library and does not call a remote service.
from math import isclose
a, b = 2+3, 2+1
assert (a,b) == (5,3)
assert a/(a+b) == .625
assert isclose((a-1)/(a+b-2), 2/3)
Python examples are provided for study and local execution; this page does not execute Python.
Common mistakes
A posterior estimate is conditional on the chosen model. MAP is not the same as a posterior mean. A small uncertainty under a misspecified model need not mean a reliable real-world answer.