Source code for sorbetto.ranking.ranking_induced_by_score

import numpy as np
from matplotlib.axes import Axes
from matplotlib.figure import Figure

from sorbetto.core.performance_ordering_induced_by_one_score import (
    PerformanceOrderingInducedByOneScore,
)
from sorbetto.ranking.abstract_ranking import AbstractRanking


[docs] class RankingInducedByScore(AbstractRanking): """ See Axiom 1 in :cite:t:`Pierard2025Foundations`. """ def __init__(self, entities, score, name=None): # Precompute a few things. vals = [score(entity.performance) for entity in entities] vals = np.asarray(vals) self._vals = vals idxs = np.argsort(vals, kind="stable") # keep the ordering in cache and create a link from entities to the sorted idxs self._sorted_idx = idxs self._dico_entities = {entity: idx for idx, entity in zip(idxs, entities)} N = len(entities) # num_lt = [ sum([v < val for v in vals]) for val in vals ] num_lt = np.searchsorted(vals, vals, side="left", sorter=idxs) self._num_ge = N - num_lt # num_le = [ sum([v <= val for v in vals]) for val in vals ] num_le = np.searchsorted(vals, vals, side="right", sorter=idxs) self._num_gt = N - num_le performance_ordering = PerformanceOrderingInducedByOneScore(score) if name is None: name = "ranking of {} entities induced by the score {}".format( len(entities), score.name ) super().__init__(entities, performance_ordering, name) @property def values(self) -> np.ndarray: return self._vals
[docs] def getAllStableRanks(self) -> np.ndarray: # In case of equivalence (equal values), the returned rank decreases with the # position in the list of entities. # TODO: Change this implementation to mimic what we did in RankingFlavor for consistency (only). # (or vice-versa?) sorted_idx = self._sorted_idx N = sorted_idx.size tmp = np.empty(N, dtype=int) tmp[sorted_idx] = np.arange(N) return N - tmp
[docs] def getStableRank(self, entity) -> int: id_entity = self._dico_entities[entity] # TODO: optimize this. all_stable_ranks = self.getAllStableRanks() return all_stable_ranks[id_entity]
[docs] def getAllMinRanks(self) -> np.ndarray: return 1 + self._num_gt
[docs] def getMinRank(self, entity) -> int: id_entity = self._dico_entities[entity] return 1 + self._num_gt[id_entity]
[docs] def getAllMaxRanks(self) -> np.ndarray: return self._num_ge
[docs] def getMaxRank(self, entity) -> int: id_entity = self._dico_entities[entity] return self._num_ge[id_entity]
[docs] def getEntitiesAtRank(self, rank: int) -> list: """ :param rank: an integer between 1 and the number of entities. :return: The list of all entities e such that min_rank(e) <= rank <= max_rank(e) """ min_ranks_all = self.getAllMinRanks() max_ranks_all = self.getAllMaxRanks() return [ entity for idx, entity in enumerate(self._entities) if min_ranks_all[idx] <= rank <= max_ranks_all[idx] ]
[docs] def draw( self, fig: Figure | None = None, ax: Axes | None = None, value_axis_label: str = "", ) -> tuple[Figure, Axes]: if value_axis_label == "": score = self.performance_ordering.score value_axis_label = 'Value taken by the score\n"{}"'.format(score.name) return AbstractRanking.draw(self, fig, ax, value_axis_label)