mixle.stats.rankings.bradley_terry module

Bradley-Terry model for paired comparisons.

Each observation is an ordered pair (winner, loser) drawn from K items; the model gives every item a latent worth w_i = exp(log_w_i) and sets

P(i beats j) = w_i / (w_i + w_j) = sigmoid(log_w_i - log_w_j).

Treating the compared pair as a uniform draw over the C(K, 2) unordered pairs makes this a proper distribution over ordered pairs:

p(winner, loser) = (1 / C(K, 2)) * sigmoid(log_w[winner] - log_w[loser]).

Worths are identified up to a global scale, so log_w is stored centered (mean zero). Estimation is the Zermelo / minorization-maximization fixed point (Hunter 2004), a few low-cost numba iterations over the K x K win-count matrix – the sufficient statistic. Unlike PlackettLuceDistribution (full orderings) this consumes pairwise data directly.

Data type: Tuple[int, int] – (winner, loser) item indices in 0..K-1 (winner != loser).

class BradleyTerryDistribution(log_w, name=None, keys=None, fit_diagnostics=None, *, _log_w_already_centered=False)[source]

Bases: SequenceEncodableProbabilityDistribution

Bradley-Terry paired-comparison model with centered log-worths log_w.

Parameters:
  • log_w (Sequence[float] | np.ndarray)

  • name (str | None)

  • keys (str | None)

  • fit_diagnostics (BradleyTerryFitDiagnostics | None)

  • _log_w_already_centered (bool)

classmethod compute_capabilities()[source]

Declare the NumPy and numba execution path used by Bradley-Terry kernels.

density(x)[source]

Return the probability of one (winner, loser) comparison.

Parameters:

x (tuple[int, int])

Return type:

float

log_density(x)[source]

Return the JOINT log-probability of one (winner, loser) comparison.

The pair is drawn uniformly from all K(K-1)/2 unordered pairs and the winner follows Bradley-Terry, so exp(log_density(...)) sums to one over all ordered pairs and exp(log_density((i, j))) + exp(log_density((j, i))) is 1/C(K, 2) – NOT one. It is not P(i beats j); that conditional is win_probability().

Parameters:

x (tuple[int, int])

Return type:

float

win_probability(i, j)[source]

Return P(i beats j | i and j are compared): sigmoid(log_w[i] - log_w[j]).

The conditional a reader of log_density expects. log_density is the joint over (which pair, uniformly) x (who won), smaller by the factor C(K, 2); this quantity satisfies win_probability(i, j) + win_probability(j, i) == 1.

Parameters:
Return type:

float

seq_log_density(x)[source]

Return vectorized log-probabilities for encoded pairwise comparisons.

Parameters:

x (ndarray)

Return type:

ndarray

sampler(seed=None)[source]

Return a sampler for paired-comparison outcomes.

Parameters:

seed (int | None)

Return type:

BradleyTerrySampler

estimator(pseudo_count=None)[source]

Return an MM estimator with this distribution’s item count.

Parameters:

pseudo_count (float | None)

Return type:

BradleyTerryEstimator

dist_to_encoder()[source]

Return the pairwise-comparison encoder used by vectorized methods.

Return type:

BradleyTerryDataEncoder

class BradleyTerrySampler(dist, seed=None)[source]

Bases: DistributionSampler

Draw (winner, loser) pairs: a uniform unordered pair, then a Bradley-Terry outcome.

Parameters:
  • dist (BradleyTerryDistribution)

  • seed (int | None)

sample(size=None, *, batched=True)[source]

Draw one comparison outcome or size iid comparison outcomes.

Parameters:
Return type:

tuple[int, int] | list[tuple[int, int]]

class BradleyTerryAccumulator(dim, keys=None)[source]

Bases: SequenceEncodableStatisticAccumulator

Accumulate the K x K win-count matrix: wins[i, j] = weighted count of i beating j.

Parameters:
update(x, weight, estimate)[source]

Update the win-count matrix from one weighted comparison.

Parameters:
Return type:

None

initialize(x, weight, rng)[source]

Initialize win counts from one weighted comparison.

Parameters:
Return type:

None

seq_update(x, weights, estimate)[source]

Update win counts from encoded pairwise comparisons.

Parameters:
Return type:

None

seq_initialize(x, weights, rng)[source]

Initialize win counts from encoded pairwise comparisons.

Parameters:
Return type:

None

combine(suff_stat)[source]

Merge observation count and win-count matrix statistics.

Return type:

BradleyTerryAccumulator

value()[source]

Return accumulated observation weight and win-count matrix.

from_value(x)[source]

Restore accumulator state from value output.

Return type:

BradleyTerryAccumulator

acc_to_encoder()[source]

Return the encoder compatible with Bradley-Terry win-count statistics.

Return type:

BradleyTerryDataEncoder

class BradleyTerryAccumulatorFactory(dim, keys=None)[source]

Bases: StatisticAccumulatorFactory

Create accumulators for Bradley-Terry win-count statistics.

Parameters:
make()[source]

Create an empty Bradley-Terry accumulator.

Return type:

BradleyTerryAccumulator

class BradleyTerryEstimator(dim, pseudo_count=None, max_iter=500, tol=1e-10, name=None, keys=None)[source]

Bases: ParameterEstimator

Maximum-likelihood log-worths via the Zermelo / MM fixed point (Hunter 2004).

pseudo_count adds that many fractional wins to EVERY ordered pair (symmetric smoothing). It is what lets an undefeated or winless competitor, or a disconnected comparison graph, fit at all: the unregularized maximum likelihood does not exist there (Ford 1957), and the estimator refuses rather than return a boundary worth. Choosing it: the top of the ranking is stable over a wide range, but near-tied competitors can swap order and the leader’s worth margin shrinks roughly with pseudo_count relative to the wins per pair, because the prior wins pull every worth toward equality (a 0.05 -> 2.0 sweep on one realistic dataset moved the leader’s margin by ~10x while leaving the top order alone). Start near 0.5, half a prior win per ordered pair, shrink it as the comparisons per pair grow, read fit_diagnostics.regularized and pseudo_count on the result, and compare two values before quoting a margin.

Parameters:
accumulator_factory()[source]

Return a factory for Bradley-Terry sufficient-statistic accumulators.

Return type:

BradleyTerryAccumulatorFactory

estimate(nobs, suff_stat)[source]

Estimate centered log-worths from accumulated win counts.

Parameters:

nobs (float | None)

Return type:

BradleyTerryDistribution

class BradleyTerryDataEncoder(dim=None)[source]

Bases: DataSequenceEncoder

Encode a sequence of (winner, loser) pairs into an (N, 2) integer array.

Parameters:

dim (int | None)

seq_encode(x)[source]

Validate and encode (winner, loser) pairs as an integer matrix.

Parameters:

x (Sequence[tuple[int, int]])

Return type:

ndarray

class BradleyTerryFitDiagnostics(converged, iterations, l1_change, regularized, pseudo_count)[source]

Bases: object

Convergence and regularization evidence attached to an estimated model.

Parameters: