Bayesian networks: why the grass is wet and what it means for the sprinkler
Joint distribution and its factorisation, Bayesian network and conditional probability tables, inference by enumeration, explaining away, d-separation and approximate inference by sampling — on the network cloudy, sprinkler, rain, wet grass.
Series AI basics Part 40 of 52
- Map of artificial intelligence: what is what and how it all fits together
- A brief history of artificial intelligence: from Turing to language models
- Data, model, training, inference: the basic terms on a single example
- How to read mathematical notation: symbols, indices, sums and quantifiers
- Sets and relations: the building blocks of definitions in AI
- Functions and mappings: why every AI model is a function
- Logic and proofs: the rules AI reasons by
- Graphs and trees: the structure that both search and neural networks stand on
- Linear algebra for machine learning: vectors, matrices and why AI mostly multiplies
- Derivatives, the gradient and the chain rule: how a model finds out which way to learn
- Gradient descent: how a model learns
- What probability is: from rolling dice to the Kolmogorov axioms
- Conditional probability and Bayes’ theorem: how to update your estimate when you learn something new
- Random variables and the cumulative distribution function: one function that tells you everything about a distribution
- Probability density and probability mass functions: why a continuous variable has zero probability at a point
- Expected value, variance and covariance: where a distribution lies, how wide it is and what goes with what
- Overview of probability distributions: Bernoulli, binomial, Poisson, uniform, normal and exponential
- Law of large numbers and central limit theorem: why averages behave so predictably
- Statistics and parameter estimation: maximum likelihood, MAP and confidence intervals
- Information theory: entropy, cross-entropy and KL divergence — where loss functions come from
- State-space search: BFS, DFS, UCS and A* with animations
- Games and adversaries: minimax, alpha-beta pruning and Monte Carlo tree search
- Constraint satisfaction: backtracking, constraint propagation and AC-3 on sudoku and a map of Czech regions
- Logic and knowledge systems: forward and backward chaining, resolution and expert systems
- Planning: STRIPS, the blocks world, heuristics from relaxation and planning in AI agents
- Local search and simulated annealing: a travelling salesman through the Czech regional capitals
- Genetic algorithms: population, crossover, mutation and selection on a backpack for a hike
- Evolution strategies and genetic programming: from the one-fifth rule to Kepler’s law
- Ant colony optimization: how a pheromone trail finds a short path
- Particle swarm optimisation: inertia, personal experience and the swarm’s experience
- Neuroevolution: evolving the weights and shape of neural networks, and the NEAT algorithm
- Fuzzy sets and membership functions: how to write down “somewhat warm”
- Fuzzy logic and probability: why “somewhat warm” does not mean “probably warm”
- Fuzzy logic: t-norms, implications and IF–THEN rules
- Fuzzy control: Mamdani and Sugeno from a fan to a pole on a cart
- Fuzzy clustering: the fuzzy c-means algorithm and points between clusters
- Neuro-fuzzy systems (ANFIS): fuzzy rules that learn from data
- Markov chains: the transition matrix, the stationary distribution and PageRank
- Hidden Markov models: the Viterbi algorithm and the dishonest casino
- Bayesian networks: why the grass is wet and what it means for the sprinkler
- The Kalman filter: how to estimate where a car is and how fast it goes from imprecise measurements
- Types of machine learning: supervised, unsupervised, semi-supervised and more
- Prompts, context and RAG: how to give a model the right information
- Variational autoencoders (VAE): new images from a continuous latent space
- Generative adversarial networks (GAN): the forger versus the detective
- Diffusion models: how pure noise becomes an image
- Markov decision processes: states, actions, rewards and the Bellman equations
- Q-learning and DQN: learning the value of actions, from a table to a neural network
- Policy gradient and PPO: learning the policy directly
- How an AI agent works: a language model in a loop with tools
- Programming with AI agents: the task, tests and review
- Evaluating and securing AI systems: how to measure and how to keep watch
Full series syllabus 52 of 83 topics published
- How a Bayesian network shrinks a huge probability table into a few small tables.
- How a network reasons from effects to causes and what explaining away is.
- How to read from the graph which variables are independent, and how probabilities are estimated by sampling.
Useful to know first: Conditional probability and Bayes’ theorem: how to update your estimate when you learn something new, Graphs and trees: the structure that both search and neural networks stand on
You step outside in the morning and the grass is wet. Did it rain, or was the sprinkler on? And when a neighbour then tells you it rained during the night — does that change what you think about the sprinkler? People reason like this without thinking. A machine can do it too, as long as it knows what is connected to what. A Bayesian network is a picture of these connections from which you can compute the answer to any question. Judea Pearl received the 2011 Turing Award for it and for the theory of causality built on top of it.
It builds on the parts Conditional probability and Bayes’ theorem and Graphs and trees.
1. The problem of the big table
Complete information about several random variables is their joint distribution — the probability of every combination of values. For four yes/no variables there are 16 combinations, so 15 independent numbers. For 37 variables (that is how many the well-known ALARM medical network for monitoring patients under anaesthesia has) it would be over 137 billion numbers, even if they were all just yes/no. Nobody can build such a table, store it or estimate it from data. What saves us is that most variables are related only indirectly.
Definition — joint distribution and the number of its parameters
Let (Ω, 𝓕, P) be a probability space (see the part What is probability), n ≥ 1, and let X1, …, Xn be discrete random variables on it (see the part Random variables); the variable Xi takes values in a finite or countable set 𝒳i, i = 1, …, n. The joint distribution of the variables X1, …, Xn is the function 𝒳1 × ⋯ × 𝒳n → [0, 1] that assigns to every combination of values (x1, …, xn) the number
P(x1, …, xn) = P({ω ∈ Ω : X1(ω) = x1 ∧ … ∧ Xn(ω) = xn}),
also written P(x1, …, xn) = P(X1 = x1, …, Xn = xn). From the axioms of probability it follows that:
- P(x1, …, xn) ≥ 0 for all (x1, …, xn) ∈ 𝒳1 × ⋯ × 𝒳n;
- ∑(x1, …, xn) ∈ 𝒳1 × ⋯ × 𝒳n P(x1, …, xn) = 1.
Number of parameters. If all the variables are two-valued (|𝒳i| = 2 for i = 1, …, n, values yes/no), the domain has 2n elements. Any 2n − 1 values can be chosen independently (non-negative, with a sum of at most 1), and the last one is determined by condition 2 as 1 minus their sum. The joint distribution of n two-valued variables therefore has
2n − 1
independent parameters — that many numbers are needed to determine it uniquely.
Calculation. 24 − 1 = 15; 237 − 1 = 137,438,953,471.
Theorem — the chain rule
Let (Ω, 𝓕, P) be a probability space, n ≥ 2, X1, …, Xn discrete random variables with values in 𝒳1, …, 𝒳n, and (x1, …, xn) ∈ 𝒳1 × ⋯ × 𝒳n a combination of values for which P(x1, …, xn−1) > 0. By P(xi | x1, …, xi−1) we mean the conditional probability (see the part on conditional probability) of the event {Xi = xi} given {X1 = x1, …, Xi−1 = xi−1}. Then
P(x1, …, xn) = P(x1) · P(x2 | x1) · P(x3 | x1, x2) ⋯ P(xn | x1, …, xn−1) = ∏i=1n P(xi | x1, …, xi−1),
where the factor for i = 1 is P(x1) (empty condition).
Proof: for k ≤ n − 1 the event {X1 = x1, …, Xk = xk} is a superset of the event {X1 = x1, …, Xn−1 = xn−1}, so it has positive probability and all the conditional probabilities in the formula are defined. By the definition of conditional probability
P(xn | x1, …, xn−1) = P(x1, …, xn)/P(x1, …, xn−1),
so P(x1, …, xn) = P(xn | x1, …, xn−1) · P(x1, …, xn−1). We apply the same to the second factor and so on, until only P(x1) is left. ∎
The chain rule saves nothing: the last factor still depends on all the preceding variables, so it is just another way of writing the same huge table. The savings come once we drop some of the conditions.
2. Bayesian network
Definition — Bayesian network
Let n ≥ 1 and let X1, …, Xn be variables, Xi with values in a finite non-empty set 𝒳i, i = 1, …, n. A Bayesian network over these variables is a pair (G, Θ), where
- G = (V, H) is a directed acyclic graph (DAG, see the part Graphs and trees) with vertex set V = {X1, …, Xn} and edge set H ⊆ V × V; the parents of the vertex Xi are parents(Xi) = {Xj ∈ V : (Xj, Xi) ∈ H};
- Θ assigns to every vertex Xi a conditional probability table: for every combination of values u of its parents a distribution P( · | u) on 𝒳i, i.e. numbers P(xi | u) ≥ 0 for xi ∈ 𝒳i such that ∑xi ∈ 𝒳i P(xi | u) = 1. A vertex without parents has a single distribution P(xi).
The network determines the joint distribution of the variables X1, …, Xn by the rule
P(x1, …, xn) = ∏i=1n P(xi | parents(Xi)) for all (x1, …, xn) ∈ 𝒳1 × ⋯ × 𝒳n,
where in the i-th factor we substitute for parents(Xi) the values the parents have in the combination (x1, …, xn). The product is non-negative and sums to 1 over all combinations (if we first sum over the values of the vertex that comes last in topological order, its factor gives 1 and the network without it remains), so it really is a joint distribution.
Arrows lead from causes to effects. For each variable it is enough to know how it depends on its direct causes — nothing more. The probability of the whole situation is the product of these local numbers. Instead of one huge table we have a few small ones.
Why may the network write just P(xi | parents) and not the whole history like the chain rule? Because it assumes conditional independences about the graph.
Definition — conditional independence
Let (Ω, 𝓕, P) be a probability space and A, C, E discrete random variables on it with values in 𝒜, 𝒞, ℰ (each of them may also be a group of variables, i.e. a vector; E may be an empty group). For short we write P(a | c, e) = P(A = a | C = c, E = e) and so on. The variables A and C are conditionally independent given E, written A ⊥ C | E, if and only if
∀a ∈ 𝒜 ∀c ∈ 𝒞 ∀e ∈ ℰ : P(c, e) > 0 ⇒ P(a | c, e) = P(a | e).
In words: once we know the value of E, knowing the value of C does not change the probability of any value of A. The equality in the definition:
P(a | c, e) = P(a | e)
- P(a | c, e)
- what we know about A when we know E and also C
- P(a | e)
- what we know about A from E alone; the equality says that C adds nothing more — the whole connection between A and C runs through E
Theorem — factorisation is the chain rule plus local independences
Let G = (V, H) be a directed acyclic graph with vertices V = {X1, …, Xn}, which are discrete random variables on a probability space (Ω, 𝓕, P), and let the vertices be numbered topologically: (Xj, Xi) ∈ H ⇒ j < i. The descendants of a vertex Xi are the vertices other than Xi to which a directed path leads from Xi; non-descendants(Xi) = V ∖ ({Xi} ∪ descendants(Xi)). Assume the local Markov condition:
∀i ∈ {1, …, n} : Xi ⊥ (non-descendants(Xi) ∖ parents(Xi)) | parents(Xi),
i.e. every variable is, given its parents, conditionally independent of all other variables that are not its descendants. Then for every combination of values (x1, …, xn) with P(x1, …, xn−1) > 0
P(x1, …, xn) = ∏i=1n P(xi | parents(Xi)).
Proof: in the chain rule in topological order we have P(xi | x1, …, xi−1). Among X1, …, Xi−1 are all the parents of Xi (a parent has a smaller number) and none of its descendants (a descendant comes after it in the order), so {X1, …, Xi−1} ⊆ non-descendants(Xi). By the Markov condition we can drop all variables except the parents from the condition, and what remains is P(xi | parents(Xi)). ∎
It also holds the other way round: every distribution given by a product of tables satisfies the local Markov condition. That is why a Bayesian network can be defined in either of the two ways.
Our network: when it is cloudy, rain is more likely and it is less likely that someone turns on the sprinkler. Both rain and the sprinkler make the grass wet. The numbers come from Kevin Murphy’s popular example:
The network has 1 + 2 + 2 + 4 = 9 numbers instead of 15. With four variables the saving is small, with hundreds it is huge: if every vertex has at most k parents, the number of numbers grows with n linearly (n · 2k), not exponentially (2n). The probability of the situation “cloudy, the sprinkler was off, it rained, the grass is wet” is 0.5 · 0.9 · 0.8 · 0.9 = 0.324 (colours as in the formula below).
P(z, p, d, t) = P(z) · P(p | z) · P(d | z) · P(t | p, d)
- P(z)
- cloudy has no parents, its table is a single number; in the example 0.5
- P(p | z)
- the sprinkler depends only on the clouds — here nothing differs from the chain rule; in the example it was off under a cloudy sky: 1 − 0.1 = 0.9
- P(d | z)
- the chain rule would want P(d | z, p); the network assumes that once the sky is known, the sprinkler says nothing about rain, so p drops out of the condition; in the example 0.8
- P(t | p, d)
- the chain rule would want P(t | z, p, d); the grass “knows” about the clouds only through rain and the sprinkler, so z drops out; in the example (sprinkler no, rain yes) 0.9
3. Inference: from effect to cause
Definition — inference by enumeration
Let (G, Θ) be a Bayesian network over the variables X1, …, Xn, and let these variables be split into three disjoint groups: the query Q (one variable with values in 𝒬), the evidence E = (E1, …, Em) with observed values e = (e1, …, em), and the hidden variables Y (all the others) with the set of value combinations 𝒴. Assume P(e) > 0. Then for every q ∈ 𝒬
P(q | e) = ∑y ∈ 𝒴 P(q, e, y)/∑q′ ∈ 𝒬 ∑y ∈ 𝒴 P(q′, e, y),
where each P(q, e, y) is a value of the joint distribution of the network — a product of numbers from the tables according to the factorisation. Inference by enumeration is the algorithm that computes by this formula:
Input: the network (G, Θ), the query variable Q, evidence E = e with P(e) > 0. Output: the numbers P(q | e) for all q ∈ 𝒬. Steps:
- For every q ∈ 𝒬 set S(q) := 0.
- For every q ∈ 𝒬 and every y ∈ 𝒴 compute the product P(q, e, y) from the tables and add it to S(q).
- After going through all (finitely many) pairs (q, y) set Z := ∑q′ ∈ 𝒬 S(q′) = P(e) and return P(q | e) = S(q)/Z for every q ∈ 𝒬.
We go through all possible worlds that agree with what we know (the grass is wet) and look at how much weight the ones where it rained have among them. It is Bayes’ theorem from the part on conditional probability, only summed over more variables at once.
P(q | e) = ∑y P(q, e, y)/∑q′, y P(q′, e, y)
- e
- evidence — the values we observed (in our case wet grass); they are fixed in all the worlds being summed
- ∑y
- we do not know the hidden variables (in our case cloudy and the sprinkler) and do not care about them, so we sum over all their possibilities — marginalisation; the worlds are mutually exclusive, so their probabilities add up
- P(q, e, y)
- the probability of one complete world in which both the query and the evidence hold — a product of numbers from the tables according to the factorisation
- ∑q′, y P(q′, e, y)
- = P(e), the weight of all worlds that agree with the evidence; the division is the definition of conditional probability P(q | e) = P(q, e)/P(e) and guarantees that ∑q P(q | e) = 1 (for a yes/no query P(Q | e) + P(¬Q | e) = 1)
Example — P(rain | wet grass) by enumeration
The evidence is T = yes, the query is D, and Z and P are hidden. There are 23 = 8 worlds with wet grass; each is the product P(z) · P(p | z) · P(d | z) · P(t | p, d):
| rain | cloudy | sprinkler | product | P(world) |
|---|---|---|---|---|
| yes | yes | yes | 0.5 · 0.1 · 0.8 · 0.99 | 0.0396 |
| yes | no | yes | 0.5 · 0.5 · 0.2 · 0.99 | 0.0495 |
| yes | yes | no | 0.5 · 0.9 · 0.8 · 0.9 | 0.3240 |
| yes | no | no | 0.5 · 0.5 · 0.2 · 0.9 | 0.0450 |
| no | yes | yes | 0.5 · 0.1 · 0.2 · 0.9 | 0.0090 |
| no | no | yes | 0.5 · 0.5 · 0.8 · 0.9 | 0.1800 |
| no | yes | no | 0.5 · 0.9 · 0.2 · 0 | 0.0000 |
| no | no | no | 0.5 · 0.5 · 0.8 · 0 | 0.0000 |
The rows where it rained are the worlds P(q, e, y) for q = rain yes; their sum over the hidden Z, P gives P(D, T) = 0.4581, the sum of all eight P(T) = 0.6471. The last two rows are zero: without rain and without the sprinkler the grass is not wet. Therefore (colours as in the formula above)
P(D | T) = 0.4581/0.6471 = 0.708.
def dotaz(Q, dukazy, sit):
citatel = jmenovatel = 0.0
for svet in vsechna_prirazeni(sit): # 2^n complete worlds
if any(svet[k] != v for k, v in dukazy.items()):
continue # disagrees with the evidence
p = 1.0
for uzel in sit: # factorisation of the network
p *= P(uzel, svet[uzel], svet[rodice(uzel)])
jmenovatel += p # → P(e)
if svet[Q]:
citatel += p # → P(Q, e)
return citatel / jmenovatel
Beforehand (without any observation) the probability of rain is 0.5 and of the sprinkler 0.3. Wet grass raises both: P(rain | wet grass) = 0.708 and P(sprinkler | wet grass) = 0.430. Rain is the more likely explanation, because it rains more often than the sprinkler runs. Wet grass also raises the probability that it was cloudy — from 0.5 to 0.576 — even though the grass and the clouds are not directly connected. Information flows through the network against the arrows.
4. Explaining away
Now we learn that it really did rain during the night. What happens to the sprinkler?
The probability of the sprinkler drops from 0.430 to 0.194. Rain has already explained the wet grass, so there is no reason left for the sprinkler. Conversely, when we know the sprinkler was on, the probability of rain falls from 0.708 to 0.320. This phenomenon is called explaining away. Two causes that were beforehand only weakly related start “pushing each other out” as soon as we observe their common effect. And if we knew that it had not rained, the sprinkler would have to have been on: P(sprinkler | wet grass, no rain) = 1, because in our network the grass cannot be wet by itself.
Example — explaining away in numbers
From the table in the previous example: the worlds where it rained, the sprinkler was on and the grass is wet together have P(P, D, T) = 0.0396 + 0.0495 = 0.0891. Hence
P(P | T, D) = P(P, D, T)/P(D, T) = 0.0891/0.4581 = 0.194,
P(D | T, P) = P(P, D, T)/P(P, T) = 0.0891/0.2781 = 0.320
(the denominator is the probability of the evidence P(e), colours as in the formula for inference by enumeration above).
Formally, explaining away is the inequality P(P | T, D) < P(P | T): confirming one cause lowers the probability of the other (0.194 < 0.430).
5. What the network tells you: d-separation
The graph does not only say how to compute — it also says which variables are independent of each other, and without a single number. All possibilities are made up of three basic shapes:
- Chain A → B → C: A and C are related, but once we know B, they are not. (Cloudy → rain → wet grass: if you know whether it rained, the clouds tell you nothing about the grass.)
- Fork A ← B → C: a common cause makes A and C dependent; once we know it, the dependence disappears. (The sprinkler and rain are related beforehand through the clouds: P(sprinkler | rain) = 0.18, but P(sprinkler | no rain) = 0.42. When we know whether it is cloudy, they are independent.)
- Collider A → B ← C: the causes are independent until we observe the common effect — then they become dependent. That is explaining away.
Definition — d-separation
Let G = (V, H) be a directed acyclic graph, A, C ∈ V distinct vertices and E ⊆ V ∖ {A, C} a set of vertices (the observed variables).
- An undirected path between A and C is a sequence of mutually distinct vertices (V0, V1, …, Vk), k ≥ 1, with V0 = A, Vk = C, such that (Vj−1, Vj) ∈ H ∨ (Vj, Vj−1) ∈ H for j = 1, …, k (neighbouring vertices are joined by an edge, the direction of the arrow does not matter).
- An inner vertex Vj of the path (0 < j < k) is the middle of a chain if and only if Vj−1 → Vj → Vj+1 or Vj−1 ← Vj ← Vj+1; a fork if and only if Vj−1 ← Vj → Vj+1; a collider if and only if Vj−1 → Vj ← Vj+1 (U → W means (U, W) ∈ H). Every inner vertex is exactly one of these three.
- A path is blocked by the set E if and only if it has an inner vertex Vj for which at least one of the following holds: (a) Vj is the middle of a chain or a fork ∧ Vj ∈ E, (b) Vj is the middle of a collider ∧ ({Vj} ∪ descendants(Vj)) ∩ E = ∅, where descendants(Vj) are the vertices to which a directed path leads from Vj.
- The vertices A and C are d-separated by the set E if and only if every undirected path between A and C is blocked by E.
Theorem (Verma and Pearl). Let (G, Θ) be a Bayesian network, P the joint distribution it determines, and A, C, E as above. If A and C are d-separated by the set E, then A ⊥ C | E with respect to P — and this for every choice of the tables Θ.
Information flows through the graph along paths. A known variable in the middle of a chain or a fork stops the flow — it is already “explained”. With a collider it is the other way round: as long as we do not know the effect, the flow stands still there; as soon as we observe it, it opens. From the picture you can thus read off what needs to be measured and what is unnecessary.
In our network, cloudy and wet grass are d-separated when we know both the sprinkler and the rain — the calculation confirms it: the probability of a cloudy sky then does not depend on the grass at all.
Example — three shapes verified by calculation
- Fork sprinkler ← cloudy → rain. Without knowing the sky: P(P | D) = 0.18 ≠ P(P) = 0.3, dependent. With the sky known: P(P | Z, D) = 0.1 = P(P | Z), so P ⊥ D | Z.
- Collider sprinkler → wet grass ← rain. With the sky known, P and D are independent (P(P | Z, D) = P(P | Z, ¬D) = 0.1), but as soon as we observe the grass, they are not: P(P | Z, D, T) = 0.109, whereas P(P | Z, ¬D, T) = 1.
- D-separation of the cloudy sky and the wet grass by the set {P, D}: both paths Z → P → T and Z → D → T are chains with a known middle, so they are blocked. And indeed: P(Z | P, D) = 0.444 and P(Z | P, D, T) = 0.444; P(Z | P, ¬D) = 0.048 and P(Z | P, ¬D, T) = 0.048.
6. Approximate inference by sampling
Inference by enumeration goes through all combinations of the hidden variables — in a general network exponentially many. Exact inference in Bayesian networks is NP-hard. For large networks the probabilities are therefore estimated by simulation.
Algorithms — rejection sampling and likelihood weighting
Both algorithms have the same input: a Bayesian network (G, Θ) over the variables X1, …, Xn numbered topologically (a parent has a smaller number than its child), a query Q = q, evidence E = e and a number of samples N ∈ ℕ, N ≥ 1; and the same output: an estimate P̂(q | e) of the number P(q | e). To draw xi means to choose a random value from 𝒳i according to the distribution P( · | u) from the table of the vertex Xi, where u are the values of its parents already determined in this sample.
Rejection sampling:
- Set Nacc := 0, Nq := 0.
- Repeat N times: for i = 1, …, n draw xi. If the sample agrees with the evidence (every evidence variable has its observed value in it), increase Nacc by 1, and if moreover Q = q holds in it, increase Nq by 1 too; otherwise throw the sample away.
- After N repetitions stop and return P̂(q | e) = Nq/Nacc (for Nacc = 0 the estimate is undefined).
Likelihood weighting:
- Set W := 0, Wq := 0.
- Repeat N times (the k-th sample): set wk := 1 and for i = 1, …, n: if Xi is an evidence variable with observed value ei, set xi := ei (do not draw) and wk := wk · P(ei | u), where u are the values of the parents in the sample; otherwise draw xi. Then W := W + wk, and if Q = q holds in the sample, also Wq := Wq + wk.
- After N repetitions stop and return P̂(q | e) = Wq/W (for W = 0 the estimate is undefined).
Rejection is honest but wasteful: when the evidence is rare, it throws away almost all samples. Likelihood weighting throws away nothing — it just gives each sample a weight according to how well it fits what we know.
def zamitani(Q, dukazy, n, sit):
prijato = ano = 0
for _ in range(n):
svet = {}
for uzel in sit: # from causes to effects
svet[uzel] = nahoda() < P(uzel, True, svet[rodice(uzel)])
if any(svet[k] != v for k, v in dukazy.items()):
continue # into the bin
prijato += 1
ano += svet[Q]
return ano / prijato
def vazena(Q, dukazy, n, sit):
s = s_ano = 0.0
for _ in range(n):
svet, w = {}, 1.0
for uzel in sit:
p = P(uzel, True, svet[rodice(uzel)])
if uzel in dukazy: # we do not draw the evidence…
svet[uzel] = dukazy[uzel]
w *= p if dukazy[uzel] else 1 - p # …but we weigh how likely it is
else:
svet[uzel] = nahoda() < p
s += w
s_ano += w * svet[Q]
return s_ano / s
P̂(Q | e) = ∑k wk [Q holds in sample k]/∑k wk, wk = ∏j P(ej | parentsk)
- wk
- the weight of the sample (green like the likelihood-weighting curve in the chart) — the product of the probabilities of all pieces of evidence ej given the values of their parents that came up in sample k: we did not draw the evidence but imposed it, so we must take into account how likely it would be given the other drawn values — otherwise the estimate would be biased
- [Q holds in sample k]
- 1 if the query holds in the sample, otherwise 0 — we count only the weight of samples in which it rained
- ∑k wk
- the total weight; dividing by it turns the sum into a fraction, just like dividing by P(e) in enumeration. Thanks to it, it does not matter that the weights do not sum to 1
Example — weights given the evidence “the grass is wet”
The only piece of evidence is T = yes, and its parents are the sprinkler and rain. The weight of a sample is therefore simply P(T = yes | p, d) from the wet grass table:
- sprinkler and rain: w = 0.99,
- only one of them: w = 0.9,
- neither: w = 0 — such a sample contributes nothing, just as rejection would throw it away.
(Colour as in the formula above.)
The weight does not depend on the sky: cloudy is not a parent of the grass.
With a hundred samples, rejection gave the estimate 0.686 and used only 70 of them — the remaining 30 had dry grass and went into the bin. With 10,000 samples (of which 6,524 were left) the estimate is 0.703, close to the exact value 0.708. The error decreases as 1/√N, as the central limit theorem says: for an estimate ten times more precise you need a hundred times more samples.
σP̂ = √p(1 − p)/Nacc, Nacc ≈ N · P(e)
- p(1 − p)
- the variance of one yes/no sample (Bernoulli distribution with probability p); it is largest for p = 0.5, when a single sample is least predictable
- Nacc
- the number of samples that actually count; in rejection only those that passed, and on average they make up the fraction P(e) — with rare evidence almost none. The variance of the mean of N independent samples is N times smaller
Example — how big an error to expect
Exactly, p = 0.708 and P(e) = P(T) = 0.6471, so out of 10,000 samples we expect about 6,471 accepted (in reality there were 6,524).
- Nacc = 70: σ = √0.708 · 0.292/70 = 0.054; actual error |0.686 − 0.708| = 0.022.
- Nacc = 6,524: σ = 0.0056; actual error 0.0050.
Both actual errors are smaller than one standard deviation — consistent with about two thirds of the estimates falling within ±σ (normal distribution by the central limit theorem).
7. Bayesian networks in practice
- Diagnosis. Medical networks (ALARM, QMR-DT with hundreds of diseases and thousands of symptoms) and fault diagnosis of machines and networks: infer the most likely cause from the observed symptoms — and suggest what to measure next.
- Learning from data. The tables can be estimated from data by counting (by the maximum likelihood method from the part on statistics), even when some values are missing — with the EM algorithm, a relative of the Baum–Welch algorithm from the previous part.
- Causality. Pearl showed that a network read as a graph of causes can also answer questions like “what would happen if we intervened” — turned on the sprinkler ourselves — which cannot be read from correlations alone. Today’s causal inference in epidemiology and economics rests on this.
- Relatives. The naive Bayes classifier is a Bayesian network with one cause and many independent effects. Hidden Markov models from the previous part are a Bayesian network unrolled in time.
8. Summary
- A Bayesian network is a directed acyclic graph with tables P(X | parents); the joint distribution is the product of these tables. Our network needs 9 numbers instead of 15.
- Inference also works against the arrows: wet grass raises the probability of rain to 0.708 and of the sprinkler to 0.430.
- Explaining away: when we know it rained, the probability of the sprinkler drops to 0.194.
- D-separation reads independences straight from the graph — a chain and a fork are closed by observation, a collider is opened.
- Exact inference is NP-hard in general; sampling gives estimates with an error decreasing as 1/√N.
Want to get your hands on it? Have an AI agent build a Bayesian network for a fault in your own car or computer (“it won’t start — the battery or the starter?”) and see how the suspicion changes as you add observations.
Do you see it differently? Write to support@coden-app.com.