| import random
|
| import json
|
|
|
| class EloRank:
|
| def __init__(self, initial_rating=1000, k_factor=32):
|
| """
|
| Initialize the EloRank class.
|
| :param initial_rating: Initial ELO rating for each model.
|
| :param k_factor: The K-factor that determines the sensitivity of rating changes.
|
| """
|
| self.ratings = {}
|
| self.initial_rating = initial_rating
|
| self.k_factor = k_factor
|
| self.wins = {}
|
|
|
| def add_model(self, model_id):
|
| """
|
| Add a new model with the initial rating.
|
| :param model_id: Unique identifier for the model.
|
| """
|
| self.ratings[model_id] = self.initial_rating
|
| self.wins[model_id] = 0
|
|
|
| def record_match(self, winner, loser):
|
| """
|
| Update the ratings based on a match result.
|
| :param winner: Model ID of the winner.
|
| :param loser: Model ID of the loser.
|
| """
|
| rating_winner = self.ratings[winner]
|
| rating_loser = self.ratings[loser]
|
|
|
| expected_winner = self.expected_score(rating_winner, rating_loser)
|
| expected_loser = self.expected_score(rating_loser, rating_winner)
|
|
|
| self.ratings[winner] += self.k_factor * (1 - expected_winner)
|
| self.ratings[loser] += self.k_factor * (0 - expected_loser)
|
|
|
|
|
| self.wins[winner] += 1
|
|
|
| def expected_score(self, rating_a, rating_b):
|
| """
|
| Calculate the expected score for a model.
|
| :param rating_a: Rating of model A.
|
| :param rating_b: Rating of model B.
|
| :return: Expected score.
|
| """
|
| return 1 / (1 + 10 ** ((rating_b - rating_a) / 400))
|
|
|
| def get_rating(self, model_id):
|
| """
|
| Get the current rating of a model.
|
| :param model_id: Unique identifier for the model.
|
| :return: Current rating of the model.
|
| """
|
| return self.ratings.get(model_id, None)
|
|
|
| def get_wins(self, model_id):
|
| """
|
| Get the number of wins of a model.
|
| :param model_id: Unique identifier for the model.
|
| :return: Number of wins of the model.
|
| """
|
| return self.wins.get(model_id, 0)
|
|
|
| def get_top_models(self, n=2):
|
| """
|
| Get the top N models by rating.
|
| :param n: Number of top models to retrieve.
|
| :return: List of model IDs of the top models.
|
| """
|
| return sorted(self.ratings, key=self.ratings.get, reverse=True)[:n]
|
|
|
| def sample_next_match(self):
|
| """
|
| Sample the next match based on the probability proportional to the current rating.
|
| This approach helps accelerate the convergence of ranking.
|
| :return: Tuple of two model IDs for the next match.
|
| """
|
| model_ids = list(self.ratings.keys())
|
| probabilities = [self.ratings[model_id] for model_id in model_ids]
|
| total_rating = sum(probabilities)
|
| probabilities = [rating / total_rating for rating in probabilities]
|
|
|
|
|
| next_match = random.choices(model_ids, probabilities, k=2)
|
| while next_match[0] == next_match[1]:
|
| next_match = random.choices(model_ids, probabilities, k=2)
|
|
|
| return tuple(next_match)
|
|
|
| def process_match_records(self, file_path):
|
| """
|
| Process match records from a JSON file and update ratings and win counts accordingly.
|
| :param file_path: Path to the JSON file containing match records.
|
| """
|
| with open(file_path, 'r') as file:
|
| match_records = json.load(file)
|
|
|
| for record in match_records:
|
| winner = record['winner']
|
| model_1 = record['model_1']
|
| model_2 = record['model_2']
|
|
|
|
|
| if model_1 not in self.ratings:
|
| self.add_model(model_1)
|
| if model_2 not in self.ratings:
|
| self.add_model(model_2)
|
|
|
|
|
| if winner == model_1:
|
| self.record_match(model_1, model_2)
|
| elif winner == model_2:
|
| self.record_match(model_2, model_1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|