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 cheap 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)[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)

classmethod compute_capabilities()[source]
density(x)[source]

Return the probability density or mass at a single observation.

Concrete default: exponentiate log_density (the abstract method subclasses must provide). Leaves with a cheaper closed form may override this.

Parameters:

x (tuple[int, int])

Return type:

float

log_density(x)[source]

Return the log-density or log-mass at a single observation.

Parameters:

x (tuple[int, int])

Return type:

float

seq_log_density(x)[source]

Return vectorized log-density values for sequence-encoded observations.

Parameters:

x (ndarray)

Return type:

ndarray

sampler(seed=None)[source]

Return a sampler for drawing observations from this distribution.

Parameters:

seed (int | None)

Return type:

BradleyTerrySampler

estimator(pseudo_count=None)[source]

Return an estimator for fitting this distribution from data.

Parameters:

pseudo_count (float | None)

Return type:

BradleyTerryEstimator

dist_to_encoder()[source]

Return the data encoder used by this distribution for 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)[source]

Draw observations.

Combinator samplers (mixture/sequence/…) accept batched. With batched=True (the default) each child stream is drawn in one vectorized call instead of a per-draw Python loop – far faster. Because every child sampler owns an independent RandomState, batching consumes each stream in the same order as the loop, so the draws are identical to the legacy path. batched=False forces that legacy per-draw loop as a guaranteed- stable reference. Leaf samplers are already vectorized and ignore the flag.

Parameters:

size (int | None)

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]
Parameters:
Return type:

None

initialize(x, weight, rng)[source]
Parameters:
Return type:

None

seq_update(x, weights, estimate)[source]
Parameters:
Return type:

None

seq_initialize(x, weights, rng)[source]
Parameters:
Return type:

None

combine(suff_stat)[source]
Return type:

BradleyTerryAccumulator

value()[source]
from_value(x)[source]
Return type:

BradleyTerryAccumulator

key_merge(stats_dict)[source]

Pool this accumulator’s statistics into stats_dict under its merge key.

The structural default implements the common single-key pattern: store the accumulator under self.keys the first time the key is seen, else combine into the one already there. Accumulators with several named keys (e.g. an HMM’s init/trans/state keys) or a non-accumulator stats payload override this. A keys of None (the default) is a no-op.

Parameters:

stats_dict (dict[str, Any])

Return type:

None

key_replace(stats_dict)[source]

Replace this accumulator’s statistics from the pooled stats_dict entry (see key_merge).

Parameters:

stats_dict (dict[str, Any])

Return type:

None

acc_to_encoder()[source]
Return type:

BradleyTerryDataEncoder

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

Bases: StatisticAccumulatorFactory

Parameters:
make()[source]
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).

Parameters:
accumulator_factory()[source]
Return type:

BradleyTerryAccumulatorFactory

estimate(nobs, suff_stat)[source]
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]

Encode the iid observation sequence x for vectorized evaluation.

Parameters:

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

Return type:

ndarray