Skip to content
BayesLab.Open the app →

Model building

Conditional probability tables: get every row right

A conditional probability table is a collection of answers to “what if these parents were known?” Here is how to build one without confusing conditional and overall probabilities.

By the BayesLab team · Updated 18 September 2026 · 6 min read

Start with the modelling question

Suppose we want to model whether a fictional delivery is late. We choose two potential predictors: heavy traffic and a vehicle fault. Define the time window first: these variables describe one delivery, not every journey a driver has ever made. Clear definitions prevent a table from quietly mixing different questions.

Use Traffic = Heavy/Light, Vehicle = Fault/OK, and Delivery = Late/On time. Connect Traffic → Delivery and Vehicle → Delivery. For this exercise the two parents are independent roots, with P(Heavy) = 30% and P(Fault) = 10%. That independence is a modelling assumption, not something guaranteed by their names.

Enumerate every parent combination

Two binary parents produce four combinations. Each row needs a complete distribution over the child’s two states. The values below are illustrative assumptions chosen to make both parents informative.

Delivery CPT, with child states Late / On time
TrafficVehicleLateOn time
HeavyFault90%10%
HeavyOK60%40%
LightFault70%30%
LightOK10%90%

Read the first row as: “Among deliveries with heavy traffic and a vehicle fault, 90% are late.” It does not say that heavy traffic and faults occur together 90% of the time. The row tells us about Delivery, conditional on a particular situation.

Build it in BayesLab

In BayesLab, start a blank network. Use Chance node (C) to add variables and the States tab to name their outcomes. Use Connect (A) to link parent to child, then select each node’s Table tab to enter its probabilities. The tables below use percentages: enter values such as 20% explicitly. Match the state labels, not just the order of the rows. Set observations in the Evidence tab and clear them between experiments.

  1. Create and name all three chance nodes and their states before entering the tables.
  2. Connect both parent nodes to Delivery. Enter the root distributions: 30%/70% for Traffic and 10%/90% for Vehicle.
  3. Fill Delivery’s four rows by matching both parent labels. Each row must total 100%.
  4. With no evidence set, inspect Delivery = Late. The expected value is 30.1%.
  5. Observe Heavy and Fault together. Late should now match that table row exactly: 90%.

Where does 30.1% come from?

Before observing the parents, we average the four rows using their probabilities. Independent roots give combination weights 0.03, 0.27, 0.07, and 0.63. These weights sum to one. They are not equal, so simply averaging 90, 60, 70, and 10 would answer the wrong question.

P(Late) = 0.03 × 0.90 + 0.27 × 0.60 + 0.07 × 0.70 + 0.63 × 0.10 = 0.301

With more parents, multiply their numbers of states to find the row count. Three binary parents require eight rows; one three-state parent and one binary parent require six. More detail brings more probabilities to justify, so add a parent because it improves the model—not just because another variable is available.

When a table looks correct but a result surprises you, use the model debugging checklist.