winning
A generalization of factor multinomial probit models that scales to millions of variables
This package prices the winner of many: N competitors whose performances can follow any noise distribution and can be correlated through common factors. One pass over a shared survival field gives all N win probabilities, and the same pass yields removal counterfactuals and photo-finish tie densities. Calibration runs in the other direction, from observed shares back to abilities. Factor probit, Luce's softmax and the finite-temperature softmin are special cases of one parameterized race.
The model, live
Six runners moved by two common luck factors; whichever draws the smallest performance wins. Drag each runner's ability and its two factor loadings, pick the noise distribution (and its skew), and the win probabilities update live — computed in your browser by the factor lattice algorithm this package ships, at verified parity with the Python. Runners loading the same factor with the same sign are teammates, opposite signs rivals; zero loadings recover the independent race, where Gumbel noise reproduces softmax exactly.
Quick start
from winning import race_probabilities, calibrate_abilities, removal_shares
p = race_probabilities(mu, V=V, D=D) # all N shares, one field pass
mu_hat = calibrate_abilities(p, V=V, D=D) # abilities back from shares
q = removal_shares(mu, V=V, D=D) # P(j wins | i removed), all pairs
Max-wins semantics for the probit literature live in
winning.probit (shares,
calibrate_utilities, supplied-covariance fitting); the
density-agnostic engine in winning.thurstone; the
paper-faithful kernels in winning.factor.
Papers
- Scalable share
calibration for factor multinomial probit models (2026, submitted). All
shares of a correlated Gaussian race in one O(QNL) pass, matrix-free
graph-Laplacian derivatives, and inversion of observed shares to utilities at
ten thousand alternatives in under a minute. The algorithm ships here as
winning.factor; every experiment is a committed script underresearch/experiments/. - Rating Formula 1: a case for non-Gaussian noise in rating systems (2026). Seventy-five seasons of grands prix, a retirement-slab noise density, a qualifying control, and a stratified test against historical bookmaker odds.
- Inferring relative ability from winning probability (SIAM, 2021). The lattice algorithm this package grew from: recovering ability densities from a vector of win probabilities, as in pari-mutuel markets.
- Who ya gonna call? and How to respond to an RFQ: the same order statistic in trading, where the best response to a request for quote is a horse race entry.
Demos
- Fit a correlated race — the inverse problem, live: drag observed shares and a correlation, and the engine calibrates standalone abilities in the browser, against the naive independent fit.
- The photo-finish circuit — interactive: the race as a resistor network, computed live in your browser by the shipped algorithm. Click a runner to delete it and watch the share flow to factor-similar survivors, against the IIA prediction.
- race_field_demo.py — one shared survival field prices every competitor by division; the naive O(N²) route against the O(N) field.
- cavity_downdate_demo.py — the rank-one cavity twin: one inverse contains every leave-one-out inverse.
- js/factor — the calibration core in the browser: dependency-free JavaScript at machine-precision parity with the Python; it powers the circuit demo above.
Heritage
winning began as the reference implementation of the SIAM paper above
and owns the core outright: the lattice machinery once split into the
thurstone package is
vendored back as winning.thurstone, and thurstone is maintained as a
compatibility shim whose imports resolve here. Legacy 1.x imports still work.
By Peter Cotton, with sibling packages at
microprediction.
Get the source
github.com/microprediction/winning
·
pip install winning
·
Research scripts