Patterns / Measuring

A proportion with an interval

A percentage without a denominator is not a finding. The Wilson interval behaves sensibly at small n, where the normal approximation falls apart.

Core ·Statistics

You meet it when#

Any rate reaches a slide. Conversion, click-through, error rate, on-time percentage, churn.

The problem#

"Conversion is 12%" is not information. 12% of 8 users is noise; 12% of 80,000 is a fact. The number alone cannot distinguish them, and the reader will assume the second.

The pattern#

python
from math import sqrt

def wilson(successes: int, n: int, z: float = 1.96) -> tuple[float, float]:
    """Confidence interval for a proportion that behaves at small n and extreme p."""
    if n == 0:
        return (0.0, 1.0)
    p = successes / n
    denom = 1 + z**2 / n
    centre = (p + z**2 / (2 * n)) / denom
    half = z * sqrt(p * (1 - p) / n + z**2 / (4 * n**2)) / denom
    return (max(0.0, centre - half), min(1.0, centre + half))

wilson(1, 8)             # (0.02, 0.47)   — 12.5%, and essentially uninformative
wilson(10_000, 80_000)   # (0.1228, 0.1272)

Same 12.5%. Completely different findings.

Why Wilson rather than the textbook formula#

The normal approximation — p ± 1.96·√(p(1−p)/n) — fails in two situations you will actually meet:

  • Small n. It produces intervals wider than the [0,1] range.
  • p near 0 or 1. At 0 successes it produces a zero-width interval, confidently asserting the rate is exactly zero.

Wilson handles both by construction. It is four lines and there is no reason to use anything else for display.

In SQL#

sql
select
    carrier,
    count(*)                                                   as flights,
    sum(case when arr_delay_min < 15 then 1 else 0 end)        as on_time,
    round(100.0 * sum(case when arr_delay_min < 15 then 1 else 0 end) / count(*), 1) as on_time_pct
from flight_delays
where cancelled = 'false'
group by carrier
having count(*) >= 50          -- do not rank on tiny denominators
order by on_time_pct desc;

That having clause is the SQL-side version of the same discipline: a leaderboard sorted by a rate will always be topped by the smallest sample.