winning

The simplest case for non-Gaussian rating systems.

Rating systems for multi-entrant contests: races, tournaments, leaderboards. Beliefs are whole densities on a lattice, free to be skewed or multimodal; each event updates them with the exact likelihood of the full finish order, computed by an O(N) chain; predictions are exact winner-of-many probabilities, dead-heat aware. Every claim is benchmarked against TrueSkill, OpenSkill, Glicko-2 and Elo on twelve datasets with market ceilings where they exist.

exact lattice whole-order updates non-Gaussian noise race-native measured, not asserted
The fastest time, the best offer and
        the most popular product are the same order statistic: winner of many.
The fastest time, the lowest offer and the most popular choice are the same computation: the distribution of the winner of many. The thurstone core does that computation efficiently on a lattice, in a way that scales to millions of variables; this package turns it into rating systems.
Beliefs are densities, not (mu, sigma) pairs. Each contestant's ability lives on a lattice with no parametric family imposed, and the race noise is an arbitrary kernel you choose: Gaussian, Student-t, or a retirement "slab" for contests where entrants can fail outright. A single update matches exact Bayes to lattice precision, and the update uses the whole finish order rather than pairwise or stagewise approximations. How →
Benchmarked on twelve datasets, prequentially. Formula 1, ATP and WTA tennis, chess, sumo, football, Halo 2, horse racing and synthetic worlds with known truth. Each event is predicted before it is observed, and the tables carry honest baselines: a uniform floor, an oracle where truth is known, and the bookmaker market as a ceiling where odds exist. The tables →
Non-Gaussian noise pays where the physics demands it. Formula 1 retirements make finishing order a mixture: pace when the car survives, a lottery when it does not. A density with a uniform "disaster" component beats every Gaussian system on 1,158 grands prix, and the same estimator, handed qualifying sessions where no retirement process exists, drives its own disaster mass to near zero. The paper (PDF) →
And an efficiency result. Against 88 races with genuinely pre-qualifying bookmaker odds, no rating system built on public results and grid data adds statistical power to the market: the optimal pool puts zero weight on every one of the six systems tested. The market's edge is knowledge of current car form. Section 5 →

Quick start

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), rating(name). That includes the shims around third-party comparators, so a benchmark row is a one-line swap. Install with pip install winning (core depends only on thurstone and numpy) or pip install winning[benchmarks] for the comparators.

Papers

Heritage

winning 1.x was the reference implementation of the SIAM paper above and is preserved: the legacy imports still work. The 2.x renovation moved the numerical core into thurstone (densities on a lattice, winner-of-many, the ability transform) and made this package the applications layer, the way timemachines sits on skaters: cores are few and stable; applications multiply, so they get their own package. By Peter Cotton, with sibling packages at microprediction.

Get the source

github.com/microprediction/winning · pip install winning · Research scripts