Python
Wilson `Score`
Interval
Statistical Methods
Confidence Interval
Data Analysis

Python implementation of the Wilson `Score` Interval?

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

The Wilson score interval is a confidence interval for a binomial proportion. It is often preferred over the simple normal approximation because it behaves better when the sample size is small or the observed proportion is near 0 or 1. In Python, the implementation is short once you understand the formula and choose how to obtain the normal critical value.

Why Use Wilson Instead of the Naive Interval

For a binomial proportion, the naive interval many people learn first is:

  • 'p_hat ± z * sqrt(p_hat * (1 - p_hat) / n)'

That approximation can perform badly when:

  • 'n is small'
  • the observed success rate is very low
  • the observed success rate is very high

The Wilson interval corrects this by shrinking the estimate toward the center in a principled way and producing more realistic bounds.

The Formula

Let:

  • 'x be the number of successes'
  • 'n be the total number of trials'
  • 'p_hat = x / n'
  • 'z be the normal critical value, such as about 1.96 for a 95% interval'

Then the Wilson interval is:

  • center = (p_hat + z^2 / (2n)) / (1 + z^2 / n)
  • margin = z / (1 + z^2 / n) * sqrt((p_hat * (1 - p_hat) + z^2 / (4n)) / n)

The lower and upper bounds are:

  • lower = center - margin
  • upper = center + margin

The result always stays in the valid probability range and behaves much better than the naive approximation near the edges.

Pure Python Implementation

You can implement it with the standard library. statistics.NormalDist provides the inverse CDF needed for the critical value.

python
1from math import sqrt
2from statistics import NormalDist
3
4
5def wilson_score_interval(successes, trials, confidence=0.95):
6    if trials <= 0:
7        raise ValueError("trials must be positive")
8    if not 0 <= successes <= trials:
9        raise ValueError("successes must be between 0 and trials")
10    if not 0 < confidence < 1:
11        raise ValueError("confidence must be between 0 and 1")
12
13    p_hat = successes / trials
14    alpha = 1.0 - confidence
15    z = NormalDist().inv_cdf(1.0 - alpha / 2.0)
16
17    denominator = 1.0 + (z ** 2) / trials
18    center = (p_hat + (z ** 2) / (2.0 * trials)) / denominator
19    margin = (z / denominator) * sqrt(
20        (p_hat * (1.0 - p_hat) + (z ** 2) / (4.0 * trials)) / trials
21    )
22
23    return center - margin, center + margin
24
25
26print(wilson_score_interval(42, 100))
27print(wilson_score_interval(1, 5))

This version is fully usable without SciPy.

Example Interpretation

Suppose an item gets 42 positive votes out of 100. The point estimate is 0.42, but the Wilson interval gives a range that expresses the uncertainty in that estimate.

If the sample is much smaller, such as 1 success in 5 trials, the Wilson interval is especially valuable because the naive approximation becomes unstable and misleading.

That is why Wilson score is popular in ranking systems, A/B testing summaries, and moderation or voting systems where sample sizes vary a lot.

Returning a Conservative Ranking Score

Many systems use the lower bound of the Wilson interval as a ranking value. That rewards items with both a good success rate and enough evidence.

python
1
2def wilson_lower_bound(successes, trials, confidence=0.95):
3    lower, _ = wilson_score_interval(successes, trials, confidence)
4    return lower
5
6
7print(wilson_lower_bound(500, 1000))
8print(wilson_lower_bound(5, 10))

This helps prevent tiny-sample items from ranking unrealistically high just because they had a perfect early record.

Edge Cases to Handle

A good implementation should check:

  • 'trials > 0'
  • '0 <= successes <= trials'
  • '0 < confidence < 1'

You should also decide what API to expose. Some code wants proportions in [0, 1], while other code prefers percentages. Keep the function in proportion space and convert only for display if needed.

Common Pitfalls

A common mistake is using the naive normal interval in small-sample cases where Wilson is a better fit.

Another mistake is forgetting to validate input, especially trials = 0, which makes the formula undefined.

People also sometimes hardcode z = 1.96 and then later claim the function supports arbitrary confidence levels. If the confidence level is configurable, compute z accordingly.

Finally, keep the interval as probabilities internally. Convert to percentages only when presenting the result to users.

Summary

  • The Wilson score interval is a better binomial proportion interval than the naive normal approximation in many practical cases
  • It is especially useful for small samples and proportions near 0 or 1
  • Python can implement it cleanly with math and statistics.NormalDist
  • A reusable function should validate successes, trials, and confidence
  • The lower bound is often used as a conservative ranking score
  • Keep the result in probability form internally and format as a percentage only for display

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.