Rating systems
This page describes the package's rating line: systems that maintain a belief about each contestant in a multi-entrant contest — a race, a tournament, a leaderboard — and update it from observed finishing orders. The design differs from the TrueSkill family in two respects. Beliefs are whole densities on a lattice rather than parametric (μ, σ) pairs, and each event is absorbed through the exact likelihood of the full finish order rather than a pairwise or stagewise decomposition. Every claim below is benchmarked against TrueSkill, OpenSkill, Glicko-2 and Elo on twelve datasets, with bookmaker markets as ceilings where odds exist.
Beliefs and updates
A contestant's ability is represented as a density on a lattice,
with no parametric family imposed: skewed and multimodal beliefs
are representable, and the race noise is a kernel of the modeller's
choosing — Gaussian, Student-t, or a mixture with a uniform
"retirement" component for contests whose entrants can fail
outright. The update applies the exact likelihood of the observed
finish order, computed by an O(N) forward chain, and a single
update reproduces exact Bayes to lattice precision. Predictions are
exact winner-of-many probabilities from the same machinery as the
race engine, including tie handling.
The construction is described in the
repository
documentation. The package separately ships
winning.ratings, a Gaussian moment-update line: beliefs
there are (μ, σ) pairs advanced by exact N-way moment
updates, the correlated-race generalization of the TrueSkill-style
factor. This page describes the density line.
Benchmark protocol
Twelve datasets: Formula 1, ATP and WTA tennis, chess, sumo, football, Halo 2, horse racing, and synthetic worlds with known generating truth. The protocol is prequential — each event is predicted before it is observed — and each table carries a uniform floor, an oracle where the truth is known, and the bookmaker market as a ceiling where odds exist. The tables live in BENCHMARKS.md and regenerate from committed scripts.
Non-Gaussian noise, and a market-efficiency result
Formula 1 retirements make finishing order a mixture: pace when the car survives, a lottery when it does not. A noise density with a uniform disaster component beats every Gaussian system tested on 1,158 grands prix, and the same estimator, handed qualifying sessions in which no retirement process exists, drives its own disaster mass to near zero — the component is measuring the physics, not absorbing slack. Against the 88 races with genuinely pre-qualifying bookmaker odds, however, no rating system built on public results and grid data adds statistical power to the market: the optimal forecast pool puts zero weight on every one of the six systems tested, and the market's edge is plausibly knowledge of current car form. Both results, with their designs and caveats, are in Rating Formula 1.
Quick start
This API is the research line, developed in the repository's src/ directory and shipping with a future release; the results above are from BENCHMARKS.md. The shipped race engine is documented on the home page.
from winning import ThurstoneRating
tr = ThurstoneRating()
tr.observe(names=["ada", "ben", "cid", "dot"], ranks=[1, 2, 3, 4])
tr.observe(names=["ada", "cid", "eve"], ranks=[1, 2, 3])
tr.win_probabilities(["ada", "cid", "eve"]) # exact field win probabilities
tr.rating("ada") # Rating(mu=..., sigma=...)
tr.leaderboard() # best-first, conservative
Every system in the package speaks the same three verbs:
observe(names, ranks),
win_probabilities(names) and rating(name),
including the shims around the third-party comparators, so a
benchmark row is a one-line swap. Install with pip install
winning (the core depends only on numpy) or pip
install winning[benchmarks] for the comparators.