liveBook · Manning

Joint probability distribution

As explained in Fabulous Adventures in Data Structures and Algorithms

A joint probability distribution assigns probabilities to combinations of outcomes from multiple random variables.

A joint probability distribution assigns probabilities to combinations of outcomes. For a person’s cold status C and recent sneezing S, each outcome is a pair: (cold, sneezed), (cold, did not sneeze), and so on. The probability of a pair comes from a prior and a conditional probability: P(C & S) = P(C) × P(S|C). If 10% of people have colds and 86% of those people sneeze, the joint probability of having a cold and sneezing is 8.6%. That is not the same as P(C|S), the probability of a cold given a sneeze. section 13.1

Table 13.1 A survey of 10,000 respondents organized in a marginal table

Cold: YES

Cold: NO

Total

Sneezed: YES

860

270

1,130

Sneezed: NO

140

8,730

8,870

Total

1,000

9,000

10,000

The survey table makes the distinction visible: 860 of all 10,000 respondents both had a cold and sneezed, while 860 of the 1,130 who sneezed had a cold. section 13.1

In C#, a joint distribution can be a categorical distribution whose categories are tuples. Start with a prior distribution for C and a likelihood function that returns a distribution for S given each value of C. Sampling the prior and then its corresponding likelihood generates paired outcomes. To represent their probabilities exactly instead, `ToJoint` visits every supported pair and assigns it a weight proportional to the prior weight multiplied by the conditional weight. Because the inputs use integer weights, the implementation uses the least common multiple of the likelihood distributions’ total weights to keep the resulting weights integral. section 13.2

Listing 13.3 Computing the joint distribution from a prior and a likelihood function
public static class Extensions
{
    [...]
    public static IDiscreteDistribution<(A, B)> ToJoint<A, B>(
        this IDiscreteDistribution<A> prior,
        Func<A, IDiscreteDistribution<B>> likelihood)
    {
        int lcm = prior.Support()
            .Select(a => likelihood(a).TotalWeight())
            .LCM(); #1
        List<(A, B)> jointSupport = [];
        List<int> jointWeight = [];
        foreach (A a in prior.Support())
        {
            var db = likelihood(a);
            foreach (B b in db.Support())
            {
                jointSupport.Add((a, b));
                jointWeight.Add(
                    prior.Weight(a) * db.Weight(b) * lcm /
                    db.TotalWeight());
            }
        }
        return jointSupport.ToCategorical(jointWeight);
    }
}

The `ToJoint` implementation shows how a prior and likelihood function become one distribution over pairs, including the integer-weight scaling. section 13.2

Once the pairs are available, the same distribution supports several operations:

  • Condition on an observation by filtering pairs to those with the observed second value, then project the first value. This yields a posterior distribution; for someone who sneezed, the cold-to-no-cold weights are 86 to 27. section 13.3
  • Combine independent quantities by using a likelihood that ignores its input. Two independent d20 rolls produce 400 possible pairs; projecting each pair to its maximum gives the distribution for rolling with advantage. section 13.5

Why an accurate test can mislead

Suppose a condition has prior odds of 1 in 30,000 and a test has 99.5% sensitivity and specificity. The joint distribution assigns weights of 199 to (condition, positive) but 29,999 to (no condition, positive). Filtering to positive results reveals why most positive tests are false positives despite the test’s accuracy: the rare condition’s prior still matters. section 13.4

How Fabulous Adventures in Data Structures and Algorithms covers it

How deep it goes
Works through sampled pairs, exact categorical weights, integer scaling, and filtering; treats discrete distributions rather than continuous ones.
Examples
Uses a cold-and-sneezing survey, paired d20 rolls, and a rare-condition test.
What it assumes
Assumes familiarity with discrete categorical distributions and sampling; develops joint probabilities from a counted survey.
What you can do after
Build it from scratch with `ToJoint`, then filter or project paired outcomes to obtain posteriors or derived distributions.
How it connects
Links conditional probability, categorical distributions, likelihood functions, Bayes’ theorem, independence, and projection.

Also explained in

Compare how 5 books explain joint probability distribution →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Fabulous Adventures in Data Structures and Algorithms. The section links point to the parts of the book it draws on.