riix.models.elo_davidson
The Elo-Davidson rating system
1"""The Elo-Davidson rating system""" 2import numpy as np 3import math 4from riix.core.base import OnlineRatingSystem 5from riix.utils.math_utils import sigmoid 6 7 8class EloDavidson(OnlineRatingSystem): 9 """ 10 Implements the Elo-Davidson rating system from https://www.researchgate.net/publication/341384358_Understanding_Draws_in_Elo_Rating_Algorithm 11 This method applies the method of handling draws proposed by Davidson to the "online" Elo rating system 12 Davidson's paper: https://www.jstor.org/stable/2283595 13 """ 14 15 rating_dim = 1 16 17 def __init__( 18 self, 19 competitors: list, 20 initial_rating: float = 0.0, # this does nothing 21 k: float = 32.0, 22 kappa: float = 1.0, # kappa = 2, sigma = 200 is equivalent to Elo with scale = 400.0 23 base: float = 10.0, 24 sigma: float = 200.0, 25 update_method: str = 'online', 26 dtype=np.float64, 27 ): 28 """ 29 Initializes the Elo rating system with the given parameters. 30 31 Parameters: 32 competitors (list): A list of competitors to be rated within the system. 33 initial_rating (float, optional): The initial Elo rating for new competitors. Defaults to 1500.0. 34 """ 35 super().__init__(competitors) 36 self.k = k 37 self.kappa = kappa 38 self.kappa_over_2 = kappa / 2.0 39 self.alpha = math.log(base) / (2.0 * sigma) 40 self.ratings = np.zeros(shape=self.num_competitors, dtype=dtype) + initial_rating 41 if update_method == 'batched': 42 self.update = self.batched_update 43 elif update_method == 'online': 44 self.update = self.online_update 45 else: 46 raise ValueError(f'update_method must be one of online or batched, got {update_method}') 47 48 def predict(self, matchups: np.ndarray, time_step: int = None, set_cache: bool = False): 49 """ 50 Generates predictions for a series of matchups between competitors. 51 Parameters: 52 matchups (np.ndarray): A NumPy array of matchups, where each row represents a matchup 53 and contains two integers indicating the indices of the competitors 54 in the 'ratings' array. 55 time_step (int, optional): A time step at which the predictions are made. This parameter 56 is not used in the current implementation but can be utilized 57 for time-dependent predictions. Defaults to None. 58 set_cache (bool, optional): If True, caches the computed probabilities in the 'cache' 59 attribute under the key 'probs'. Defaults to False. 60 61 Returns: 62 np.ndarray: A NumPy array containing the predicted probabilities for the first competitor 63 in each matchup winning against the second. 64 """ 65 ratings_1 = self.ratings[matchups[:, 0]] 66 ratings_2 = self.ratings[matchups[:, 1]] 67 probs = sigmoid(self.alpha * (ratings_1 - ratings_2)) 68 return probs 69 70 def get_pre_match_ratings(self, matchups: np.ndarray, **kwargs): 71 return self.ratings[matchups] 72 73 def batched_update(self, matchups, outcomes, use_cache): 74 """ 75 Apply a single update based on all results of the rating period. 76 77 Parameters: 78 matchups: Matchup information for the rating period. 79 outcomes: Results of the matchups. 80 use_cache: Flag to use cached probabilities or calculate anew. 81 """ 82 raise NotImplementedError 83 84 def online_update(self, matchups, outcomes, **kwargs): 85 """ 86 Treats the matchups in the rating period as sequential events. 87 88 Parameters: 89 matchups: Sequential matchups in the rating period. 90 outcomes: Results of each matchup. 91 **kwargs: Additional parameters (not used). 92 """ 93 for idx in range(matchups.shape[0]): 94 comp_1, comp_2 = matchups[idx] 95 r_1 = self.ratings[comp_1] 96 r_2 = self.ratings[comp_2] 97 98 diff = math.exp(self.alpha * (r_1 - r_2)) 99 denom = diff + (1.0 / diff) + self.kappa 100 101 p_1 = (diff + self.kappa_over_2) / denom 102 p_2 = ((1.0 / diff) + self.kappa_over_2) / denom 103 104 update_1 = self.k * (outcomes[idx] - p_1) 105 update_2 = self.k * (1.0 - outcomes[idx] - p_2) 106 107 self.ratings[comp_1] += update_1 108 self.ratings[comp_2] += update_2 109 110 def print_leaderboard(self, num_places): 111 sorted_idxs = np.argsort(-self.ratings)[:num_places] 112 max_len = min(np.max([len(comp) for comp in self.competitors] + [10]), 25) 113 print(f'{"competitor": <{max_len}}\t{"rating"}') 114 for p_idx in range(num_places): 115 comp_idx = sorted_idxs[p_idx] 116 print(f'{self.competitors[comp_idx]: <{max_len}}\t{self.ratings[comp_idx]:.6f}')
9class EloDavidson(OnlineRatingSystem): 10 """ 11 Implements the Elo-Davidson rating system from https://www.researchgate.net/publication/341384358_Understanding_Draws_in_Elo_Rating_Algorithm 12 This method applies the method of handling draws proposed by Davidson to the "online" Elo rating system 13 Davidson's paper: https://www.jstor.org/stable/2283595 14 """ 15 16 rating_dim = 1 17 18 def __init__( 19 self, 20 competitors: list, 21 initial_rating: float = 0.0, # this does nothing 22 k: float = 32.0, 23 kappa: float = 1.0, # kappa = 2, sigma = 200 is equivalent to Elo with scale = 400.0 24 base: float = 10.0, 25 sigma: float = 200.0, 26 update_method: str = 'online', 27 dtype=np.float64, 28 ): 29 """ 30 Initializes the Elo rating system with the given parameters. 31 32 Parameters: 33 competitors (list): A list of competitors to be rated within the system. 34 initial_rating (float, optional): The initial Elo rating for new competitors. Defaults to 1500.0. 35 """ 36 super().__init__(competitors) 37 self.k = k 38 self.kappa = kappa 39 self.kappa_over_2 = kappa / 2.0 40 self.alpha = math.log(base) / (2.0 * sigma) 41 self.ratings = np.zeros(shape=self.num_competitors, dtype=dtype) + initial_rating 42 if update_method == 'batched': 43 self.update = self.batched_update 44 elif update_method == 'online': 45 self.update = self.online_update 46 else: 47 raise ValueError(f'update_method must be one of online or batched, got {update_method}') 48 49 def predict(self, matchups: np.ndarray, time_step: int = None, set_cache: bool = False): 50 """ 51 Generates predictions for a series of matchups between competitors. 52 Parameters: 53 matchups (np.ndarray): A NumPy array of matchups, where each row represents a matchup 54 and contains two integers indicating the indices of the competitors 55 in the 'ratings' array. 56 time_step (int, optional): A time step at which the predictions are made. This parameter 57 is not used in the current implementation but can be utilized 58 for time-dependent predictions. Defaults to None. 59 set_cache (bool, optional): If True, caches the computed probabilities in the 'cache' 60 attribute under the key 'probs'. Defaults to False. 61 62 Returns: 63 np.ndarray: A NumPy array containing the predicted probabilities for the first competitor 64 in each matchup winning against the second. 65 """ 66 ratings_1 = self.ratings[matchups[:, 0]] 67 ratings_2 = self.ratings[matchups[:, 1]] 68 probs = sigmoid(self.alpha * (ratings_1 - ratings_2)) 69 return probs 70 71 def get_pre_match_ratings(self, matchups: np.ndarray, **kwargs): 72 return self.ratings[matchups] 73 74 def batched_update(self, matchups, outcomes, use_cache): 75 """ 76 Apply a single update based on all results of the rating period. 77 78 Parameters: 79 matchups: Matchup information for the rating period. 80 outcomes: Results of the matchups. 81 use_cache: Flag to use cached probabilities or calculate anew. 82 """ 83 raise NotImplementedError 84 85 def online_update(self, matchups, outcomes, **kwargs): 86 """ 87 Treats the matchups in the rating period as sequential events. 88 89 Parameters: 90 matchups: Sequential matchups in the rating period. 91 outcomes: Results of each matchup. 92 **kwargs: Additional parameters (not used). 93 """ 94 for idx in range(matchups.shape[0]): 95 comp_1, comp_2 = matchups[idx] 96 r_1 = self.ratings[comp_1] 97 r_2 = self.ratings[comp_2] 98 99 diff = math.exp(self.alpha * (r_1 - r_2)) 100 denom = diff + (1.0 / diff) + self.kappa 101 102 p_1 = (diff + self.kappa_over_2) / denom 103 p_2 = ((1.0 / diff) + self.kappa_over_2) / denom 104 105 update_1 = self.k * (outcomes[idx] - p_1) 106 update_2 = self.k * (1.0 - outcomes[idx] - p_2) 107 108 self.ratings[comp_1] += update_1 109 self.ratings[comp_2] += update_2 110 111 def print_leaderboard(self, num_places): 112 sorted_idxs = np.argsort(-self.ratings)[:num_places] 113 max_len = min(np.max([len(comp) for comp in self.competitors] + [10]), 25) 114 print(f'{"competitor": <{max_len}}\t{"rating"}') 115 for p_idx in range(num_places): 116 comp_idx = sorted_idxs[p_idx] 117 print(f'{self.competitors[comp_idx]: <{max_len}}\t{self.ratings[comp_idx]:.6f}')
Implements the Elo-Davidson rating system from https://www.researchgate.net/publication/341384358_Understanding_Draws_in_Elo_Rating_Algorithm This method applies the method of handling draws proposed by Davidson to the "online" Elo rating system Davidson's paper: https://www.jstor.org/stable/2283595
18 def __init__( 19 self, 20 competitors: list, 21 initial_rating: float = 0.0, # this does nothing 22 k: float = 32.0, 23 kappa: float = 1.0, # kappa = 2, sigma = 200 is equivalent to Elo with scale = 400.0 24 base: float = 10.0, 25 sigma: float = 200.0, 26 update_method: str = 'online', 27 dtype=np.float64, 28 ): 29 """ 30 Initializes the Elo rating system with the given parameters. 31 32 Parameters: 33 competitors (list): A list of competitors to be rated within the system. 34 initial_rating (float, optional): The initial Elo rating for new competitors. Defaults to 1500.0. 35 """ 36 super().__init__(competitors) 37 self.k = k 38 self.kappa = kappa 39 self.kappa_over_2 = kappa / 2.0 40 self.alpha = math.log(base) / (2.0 * sigma) 41 self.ratings = np.zeros(shape=self.num_competitors, dtype=dtype) + initial_rating 42 if update_method == 'batched': 43 self.update = self.batched_update 44 elif update_method == 'online': 45 self.update = self.online_update 46 else: 47 raise ValueError(f'update_method must be one of online or batched, got {update_method}')
Initializes the Elo rating system with the given parameters.
Arguments:
- competitors (list): A list of competitors to be rated within the system.
- initial_rating (float, optional): The initial Elo rating for new competitors. Defaults to 1500.0.
49 def predict(self, matchups: np.ndarray, time_step: int = None, set_cache: bool = False): 50 """ 51 Generates predictions for a series of matchups between competitors. 52 Parameters: 53 matchups (np.ndarray): A NumPy array of matchups, where each row represents a matchup 54 and contains two integers indicating the indices of the competitors 55 in the 'ratings' array. 56 time_step (int, optional): A time step at which the predictions are made. This parameter 57 is not used in the current implementation but can be utilized 58 for time-dependent predictions. Defaults to None. 59 set_cache (bool, optional): If True, caches the computed probabilities in the 'cache' 60 attribute under the key 'probs'. Defaults to False. 61 62 Returns: 63 np.ndarray: A NumPy array containing the predicted probabilities for the first competitor 64 in each matchup winning against the second. 65 """ 66 ratings_1 = self.ratings[matchups[:, 0]] 67 ratings_2 = self.ratings[matchups[:, 1]] 68 probs = sigmoid(self.alpha * (ratings_1 - ratings_2)) 69 return probs
Generates predictions for a series of matchups between competitors.
Arguments:
- matchups (np.ndarray): A NumPy array of matchups, where each row represents a matchup and contains two integers indicating the indices of the competitors in the 'ratings' array.
- time_step (int, optional): A time step at which the predictions are made. This parameter is not used in the current implementation but can be utilized for time-dependent predictions. Defaults to None.
- set_cache (bool, optional): If True, caches the computed probabilities in the 'cache' attribute under the key 'probs'. Defaults to False.
Returns:
np.ndarray: A NumPy array containing the predicted probabilities for the first competitor in each matchup winning against the second.
71 def get_pre_match_ratings(self, matchups: np.ndarray, **kwargs): 72 return self.ratings[matchups]
Returns the ratings for competitors at the timestep of the matchups Useful when using pre-match ratings as features in downstream ML pipelines
Arguments:
- matchups (np.ndarray of shape (n,2)): competitor indices
- time_step (optional int)
Returns:
np.ndarray of shape (n,2): ratings for specified competitors
74 def batched_update(self, matchups, outcomes, use_cache): 75 """ 76 Apply a single update based on all results of the rating period. 77 78 Parameters: 79 matchups: Matchup information for the rating period. 80 outcomes: Results of the matchups. 81 use_cache: Flag to use cached probabilities or calculate anew. 82 """ 83 raise NotImplementedError
Apply a single update based on all results of the rating period.
Arguments:
- matchups: Matchup information for the rating period.
- outcomes: Results of the matchups.
- use_cache: Flag to use cached probabilities or calculate anew.
85 def online_update(self, matchups, outcomes, **kwargs): 86 """ 87 Treats the matchups in the rating period as sequential events. 88 89 Parameters: 90 matchups: Sequential matchups in the rating period. 91 outcomes: Results of each matchup. 92 **kwargs: Additional parameters (not used). 93 """ 94 for idx in range(matchups.shape[0]): 95 comp_1, comp_2 = matchups[idx] 96 r_1 = self.ratings[comp_1] 97 r_2 = self.ratings[comp_2] 98 99 diff = math.exp(self.alpha * (r_1 - r_2)) 100 denom = diff + (1.0 / diff) + self.kappa 101 102 p_1 = (diff + self.kappa_over_2) / denom 103 p_2 = ((1.0 / diff) + self.kappa_over_2) / denom 104 105 update_1 = self.k * (outcomes[idx] - p_1) 106 update_2 = self.k * (1.0 - outcomes[idx] - p_2) 107 108 self.ratings[comp_1] += update_1 109 self.ratings[comp_2] += update_2
Treats the matchups in the rating period as sequential events.
Arguments:
- matchups: Sequential matchups in the rating period.
- outcomes: Results of each matchup.
- **kwargs: Additional parameters (not used).
111 def print_leaderboard(self, num_places): 112 sorted_idxs = np.argsort(-self.ratings)[:num_places] 113 max_len = min(np.max([len(comp) for comp in self.competitors] + [10]), 25) 114 print(f'{"competitor": <{max_len}}\t{"rating"}') 115 for p_idx in range(num_places): 116 comp_idx = sorted_idxs[p_idx] 117 print(f'{self.competitors[comp_idx]: <{max_len}}\t{self.ratings[comp_idx]:.6f}')
Prints the leaderboard of the rating system.
Arguments:
- num_places int: The number of top places to display on the leaderboard.