Problem 577064 · easy · Level 05 Advanced Algorithms & Graphs

The New Goalkeeper's Save Rate

Bayesian updating · Beta prior · posterior mean · prior strength

A football club signs a new goalkeeper and wants to track her penalty save rate θ. Goalkeepers in the league save about a quarter of penalties, so the club starts from the belief Beta(a, b): a distribution on 0 to 1 with mean a / (a + b) that behaves as if a saves and b goals had already been seen. Each new penalty updates it: a save turns Beta(a, b) into Beta(a + 1, b), a goal into Beta(a, b + 1).

Write keeper_posterior(a, b, saves), where saves lists the penalties in order (1 for a save, 0 for a goal), and return a dict:

  • "posterior": the tuple (a', b') of the final Beta distribution,
  • "mean": its mean a' / (a' + b'),
  • "mode": its most likely value (a' - 1) / (a' + b' - 2) if a' > 1 and b' > 1, otherwise None,
  • "trace": the list of posterior means after each penalty, in order,
  • "prior_share": (a + b) / (a + b + n) with n = len(saves), the weight the posterior mean still gives to the prior mean (the rest goes to the observed save rate).

Examples

Input:  a = 2, b = 6, saves = [1, 0, 0, 1, 1]
Output: {"posterior": (5, 8), "mean": 0.38461538461538464, "mode": 0.36363636363636365,
         "trace": [0.3333333333333333, 0.3, 0.2727272727272727, 0.3333333333333333, 0.38461538461538464],
         "prior_share": 0.6153846153846154}
Explanation: she saved 3 of 5 (60%), but the prior (mean 25%) still carries 8/13 of the
weight: 0.615 * 0.25 + 0.385 * 0.6 = 0.385.

Input:  a = 1, b = 1, saves = [0, 0, 0]
Output: {"posterior": (1, 4), "mean": 0.2, "mode": None,
         "trace": [0.3333333333333333, 0.25, 0.2], "prior_share": 0.4}

Constraints

  • a > 0, b > 0 (integers or floats), 0 <= len(saves) <= 10**5
  • floats are compared with a tolerance of 1e-6

Goals

  • Update a Beta prior one observation at a time
  • Summarise a Beta posterior by its mean and mode
  • See how the weight of the prior shrinks as data arrives
Starting Python…