Bayesian average
algorithm implementation
binary rating system
statistics
data analysis

How to implement the Bayesian average algorithm for a binary rating system

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

A plain average is unstable in binary rating systems when an item has only a few votes. An item with one upvote and zero downvotes looks perfect under a naive average, even though the evidence is weak. A Bayesian average fixes that by combining observed votes with a prior belief so small vote counts are smoothed toward a sensible baseline.

Core Sections

Model the rating with a Beta prior

For a binary system, each vote is either positive or negative. That fits naturally with a Bernoulli process, and the standard Bayesian prior for a Bernoulli probability is the Beta distribution.

Let:

  • 'u be the number of upvotes'
  • 'd be the number of downvotes'
  • 'n = u + d'

If the prior is Beta(alpha, beta), then the posterior mean is:

  • '(u + alpha) / (u + d + alpha + beta)'

That posterior mean is the Bayesian average for the item.

The intuition is simple:

  • 'alpha behaves like prior pseudo-upvotes'
  • 'beta behaves like prior pseudo-downvotes'
  • larger alpha + beta means stronger smoothing

A direct implementation

A minimal implementation is short once the formula is clear.

python
1def bayesian_binary_score(upvotes: int, downvotes: int, alpha: float, beta: float) -> float:
2    total = upvotes + downvotes
3    return (upvotes + alpha) / (total + alpha + beta)
4
5
6print(bayesian_binary_score(3, 2, alpha=6.5, beta=3.5))
7print(bayesian_binary_score(1, 0, alpha=6.5, beta=3.5))

This already improves ranking behavior compared with a naive average, because low-vote items are pulled toward the prior instead of jumping immediately to extremes.

Choose the prior from platform behavior

The prior should usually come from the overall system rather than from arbitrary constants. If the global positive rate across the platform is p_global and you want the prior to behave like m pseudo-votes, then:

  • 'alpha = p_global * m'
  • 'beta = (1 - p_global) * m'
python
1from dataclasses import dataclass
2
3@dataclass
4class Prior:
5    alpha: float
6    beta: float
7
8
9def build_prior(global_positive_rate: float, strength: int) -> Prior:
10    alpha = global_positive_rate * strength
11    beta = (1.0 - global_positive_rate) * strength
12    return Prior(alpha=alpha, beta=beta)
13
14
15prior = build_prior(global_positive_rate=0.65, strength=10)
16print(prior)

This makes the prior interpretable. A prior strength of 10 means a new item behaves roughly as though it already had ten platform-typical votes before receiving real user feedback.

Compare Bayesian average with naive average

The benefit becomes obvious when you compare items with tiny sample sizes.

python
1def naive_average(upvotes: int, downvotes: int) -> float:
2    total = upvotes + downvotes
3    return upvotes / total if total else 0.0
4
5
6items = {
7    "new_item": (1, 0),
8    "established_item": (80, 20),
9}
10
11prior = build_prior(global_positive_rate=0.65, strength=10)
12
13for item_id, (u, d) in items.items():
14    print(
15        item_id,
16        "naive=", round(naive_average(u, d), 4),
17        "bayesian=", round(bayesian_binary_score(u, d, prior.alpha, prior.beta), 4),
18    )

The new item still scores well, but not unrealistically well. That is the entire point of the smoothing.

Tuning prior strength

The prior strength controls how quickly items move away from the baseline.

  • small prior strength means fast reaction to new votes
  • large prior strength means more stability and slower movement

There is no universal best value. A good practical workflow is to replay historical data, rank items with several candidate strengths, and compare downstream metrics such as engagement, conversion, or moderation quality. The right setting depends on how noisy your voting system is and how much you want to protect the ranking from early randomness.

Mean score versus conservative ranking

The posterior mean is a good baseline metric, but it is not the only Bayesian ranking approach. Some systems prefer a lower confidence bound when they want to rank more conservatively and avoid over-promoting lightly rated items. That is a different ranking strategy from the posterior mean, even though both start from the same probabilistic model.

For many product systems, the posterior mean is already a major improvement over the naive ratio and is much easier to explain.

Common Pitfalls

  • Using the plain upvote ratio for low-vote items produces rankings that swing wildly on tiny amounts of evidence.
  • Choosing alpha and beta arbitrarily instead of grounding them in the platform’s global positive rate makes the prior harder to justify.
  • Setting prior strength too high can bury genuinely strong new items for too long.
  • Treating the posterior mean as the only possible Bayesian ranking method ignores cases where a more conservative confidence-based ordering is needed.
  • Forgetting to recompute the prior as platform behavior changes can leave the smoothing calibrated to outdated vote patterns.

Summary

  • In a binary rating system, the Bayesian average is the posterior mean under a Beta-Bernoulli model.
  • The scoring formula is (u + alpha) / (u + d + alpha + beta).
  • 'alpha and beta can be derived from the global positive rate and a tunable prior strength.'
  • The prior smooths noisy early votes toward a platform-level baseline.
  • Tuning the prior strength is a product decision and should be validated against real historical behavior.

Course illustration
Course illustration

All Rights Reserved.