def test_one_on_one(self): game_info = GlickoGameInfo() player1 = Team({1: (1500, 200)}) player2 = Team({2: (1400, 30)}) player3 = Team({3: (1550, 100)}) player4 = Team({4: (1700, 300)}) matches = Matches([Match([player1, player2], [1, 2]), Match([player1, player3], [2, 1]), Match([player1, player4], [2, 1])]) new_ratings = self.calculator.new_ratings(matches, 1, game_info) # self.assertMatchQuality(1.0, self.calculator.calculate_match_quality(matches, game_info)) self.assertRating(1464.1, 151.4, new_ratings.rating_by_id(1))
def updated_ratings(self): results = Match() for current_team in self.prior_layer.output_variables_groups: team_results = Team() for current_player, current_player_rating in [(player.key, player.value) for player in current_team]: new_rating = GaussianRating(current_player_rating.mean, current_player_rating.stdev) team_results[current_player] = new_rating results.append(team_results) return results
def updated_ratings(self): results = Match() for current_team in self.prior_layer.output_variables_groups: team_results = Team() for current_player, current_player_rating in [ (player.key, player.value) for player in current_team ]: new_rating = GaussianRating(current_player_rating.mean, current_player_rating.stdev) team_results[current_player] = new_rating results.append(team_results) return results
def test_two_on_four_on_two_win_draw(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (40.0, 4.0), 2: (45.0, 3.0) }, { 3: (20.0, 7.0), 4: (19.0, 6.0), 5: (30.0, 9.0), 6: (10.0, 4.0) }, { 7: (50.0, 5.0), 8: (30.0, 2.0) }], rank=[1, 2, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.367, self.calculator.match_quality(teams, game_info)) self.assertRating(40.877, 3.840, new_ratings.rating_by_id(1)) self.assertRating(45.493, 2.934, new_ratings.rating_by_id(2)) self.assertRating(19.609, 6.396, new_ratings.rating_by_id(3)) self.assertRating(18.712, 5.625, new_ratings.rating_by_id(4)) self.assertRating(29.353, 7.673, new_ratings.rating_by_id(5)) self.assertRating(9.872, 3.891, new_ratings.rating_by_id(6)) self.assertRating(48.830, 4.590, new_ratings.rating_by_id(7)) self.assertRating(29.813, 1.976, new_ratings.rating_by_id(8))
def test_one_on_seven(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3), 3: (25.0, 25.0 / 3), 4: (25.0, 25.0 / 3), 5: (25.0, 25.0 / 3), 6: (25.0, 25.0 / 3), 7: (25.0, 25.0 / 3), 8: (25.0, 25.0 / 3) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.000, self.calculator.match_quality(teams, game_info)) self.assertRating(40.582, 7.917, new_ratings.rating_by_id(1)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(2)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(3)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(4)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(5)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(6)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(7)) self.assertRating(9.418, 7.917, new_ratings.rating_by_id(8))
def test_five_teams_of_one_not_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }, { 4: (25.0, 25.0 / 3) }, { 5: (25.0, 25.0 / 3) }], rank=[1, 2, 3, 4, 5]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.040, self.calculator.match_quality(teams, game_info)) self.assertRating(34.363135705841188, 6.1361528798112692, new_ratings.rating_by_id(1)) self.assertRating(29.058448805636779, 5.5358352402833413, new_ratings.rating_by_id(2)) self.assertRating(25.000000000031758, 5.4200805474429847, new_ratings.rating_by_id(3)) self.assertRating(20.941551194426314, 5.5358352402709672, new_ratings.rating_by_id(4)) self.assertRating(15.636864294158848, 6.136152879829349, new_ratings.rating_by_id(5))
def test_eight_teams_of_one_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }, { 4: (25.0, 25.0 / 3) }, { 5: (25.0, 25.0 / 3) }, { 6: (25.0, 25.0 / 3) }, { 7: (25.0, 25.0 / 3) }, { 8: (25.0, 25.0 / 3) }], rank=[1, 1, 1, 1, 1, 1, 1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.004, self.calculator.match_quality(teams, game_info)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(1)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(2)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(3)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(4)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(5)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(6)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(7)) self.assertRating(25.000, 4.592, new_ratings.rating_by_id(8))
def test_four_on_four(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3), 2: (25.0, 25.0 / 3), 3: (25.0, 25.0 / 3), 4: (25.0, 25.0 / 3) }, { 5: (25.0, 25.0 / 3), 6: (25.0, 25.0 / 3), 7: (25.0, 25.0 / 3), 8: (25.0, 25.0 / 3) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.447, self.calculator.match_quality(teams, game_info)) self.assertRating(27.198, 8.059, new_ratings.rating_by_id(1)) self.assertRating(27.198, 8.059, new_ratings.rating_by_id(2)) self.assertRating(27.198, 8.059, new_ratings.rating_by_id(3)) self.assertRating(27.198, 8.059, new_ratings.rating_by_id(4)) self.assertRating(22.802, 8.059, new_ratings.rating_by_id(5)) self.assertRating(22.802, 8.059, new_ratings.rating_by_id(6)) self.assertRating(22.802, 8.059, new_ratings.rating_by_id(7)) self.assertRating(22.802, 8.059, new_ratings.rating_by_id(8))
def test_eight_teams_of_one_upset(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (10.0, 8.0) }, { 2: (15.0, 7.0) }, { 3: (20.0, 6.0) }, { 4: (25.0, 5.0) }, { 5: (30.0, 4.0) }, { 6: (35.0, 3.0) }, { 7: (40.0, 2.0) }, { 8: (45.0, 1.0) }], rank=[1, 2, 3, 4, 5, 6, 7, 8]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.000, self.calculator.match_quality(teams, game_info)) self.assertRating(35.135, 4.506, new_ratings.rating_by_id(1)) self.assertRating(32.585, 4.037, new_ratings.rating_by_id(2)) self.assertRating(31.329, 3.756, new_ratings.rating_by_id(3)) self.assertRating(30.984, 3.453, new_ratings.rating_by_id(4)) self.assertRating(31.751, 3.064, new_ratings.rating_by_id(5)) self.assertRating(34.051, 2.541, new_ratings.rating_by_id(6)) self.assertRating(38.263, 1.849, new_ratings.rating_by_id(7)) self.assertRating(44.118, 0.983, new_ratings.rating_by_id(8))
def test_one_on_one(self): game_info = EloGameInfo(1200, 200) teams = Match([{1: (1200, 25)}, {2: (1400, 25)}], [1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.4805, self.calculator.match_quality(teams, game_info)) self.assertRating(1218.99, new_ratings.rating_by_id(1)) self.assertRating(1381.01, new_ratings.rating_by_id(2))
def test_two_player_not_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{1: (25.0, 25.0 / 3)}, {2: (25.0, 25.0 / 3)}], [1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.447214, self.calculator.match_quality(teams, game_info)) self.assertRating(29.39583201999924, 7.171475587326186, new_ratings.rating_by_id(1)) self.assertRating(20.60416798000076, 7.171475587326186, new_ratings.rating_by_id(2))
def new_ratings(self, teams, game_info=None): game_info = TrueSkillGameInfo.ensure_game_info(game_info) self.validate_team_and_player_counts(teams) teams.sort() return Match([ self.new_team_ratings(teams[0], teams[1], teams.comparison(0, 1), game_info), self.new_team_ratings(teams[1], teams[0], teams.comparison(1, 0), game_info) ])
def test_one_on_one_massive_upset_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (50.0, 25.0 / 2) }], rank=[1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.110, self.calculator.match_quality(teams, game_info)) self.assertRating(31.662, 7.137, new_ratings.rating_by_id(1)) self.assertRating(35.010, 7.910, new_ratings.rating_by_id(2))
def test_two_player_chess_not_drawn(self): game_info = TrueSkillGameInfo(1200.0, 1200.0 / 3, 200.0, 1200.0 / 300, 0.03) teams = Match([{ 1: (1301.0007, 42.9232) }, { 2: (1188.7560, 42.5570) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertRating(1304.7820836053318, 42.843513887848658, new_ratings.rating_by_id(1)) self.assertRating(1185.0383099003536, 42.485604606897752, new_ratings.rating_by_id(2))
def test_one_on_two_draw(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3), 3: (25.0, 25.0 / 3) }], rank=[1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.135, self.calculator.match_quality(teams, game_info)) self.assertRating(31.660, 7.138, new_ratings.rating_by_id(1)) self.assertRating(18.340, 7.138, new_ratings.rating_by_id(2)) self.assertRating(18.340, 7.138, new_ratings.rating_by_id(3))
def test_one_on_two_somewhat_balanced(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (40.0, 6.0) }, { 2: (20.0, 7.0), 3: (25.0, 8.0) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.478, self.calculator.match_quality(teams, game_info)) self.assertRating(42.744, 5.602, new_ratings.rating_by_id(1)) self.assertRating(16.266, 6.359, new_ratings.rating_by_id(2)) self.assertRating(20.123, 7.028, new_ratings.rating_by_id(3))
def test_two_player_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }], rank=[1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.447, self.calculator.match_quality(teams, game_info)) self.assertRating(25.0, 6.4575196623173081, new_ratings.rating_by_id(1)) self.assertRating(25.0, 6.4575196623173081, new_ratings.rating_by_id(2))
def test_three_teams_of_one_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }], rank=[1, 1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.200, self.calculator.match_quality(teams, game_info)) self.assertRating(25.0, 5.698, new_ratings.rating_by_id(1)) self.assertRating(25.0, 5.695, new_ratings.rating_by_id(2)) self.assertRating(25.0, 5.698, new_ratings.rating_by_id(3))
def test_one_on_three_draw(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3), 3: (25.0, 25.0 / 3), 4: (25.0, 25.0 / 3) }], rank=[1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.012, self.calculator.match_quality(teams, game_info)) self.assertRating(34.990, 7.455, new_ratings.rating_by_id(1)) self.assertRating(15.010, 7.455, new_ratings.rating_by_id(2)) self.assertRating(15.010, 7.455, new_ratings.rating_by_id(3)) self.assertRating(15.010, 7.455, new_ratings.rating_by_id(4))
def test_two_on_two(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3), 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3), 4: (25.0, 25.0 / 3) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.447, self.calculator.match_quality(teams, game_info)) self.assertRating(28.108, 7.774, new_ratings.rating_by_id(1)) self.assertRating(28.108, 7.774, new_ratings.rating_by_id(2)) self.assertRating(21.892, 7.774, new_ratings.rating_by_id(3)) self.assertRating(21.892, 7.774, new_ratings.rating_by_id(4))
def test_two_on_two_unbalanced_draw(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (15.0, 8.0), 2: (20.0, 6.0) }, { 3: (25.0, 4.0), 4: (30.0, 3.0) }], rank=[1, 1]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.214, self.calculator.match_quality(teams, game_info)) self.assertRating(21.570, 6.556, new_ratings.rating_by_id(1)) self.assertRating(23.696, 5.418, new_ratings.rating_by_id(2)) self.assertRating(23.357, 3.833, new_ratings.rating_by_id(3)) self.assertRating(29.075, 2.931, new_ratings.rating_by_id(4))
def test_two_on_two_upset(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (20.0, 8.0), 2: (25.0, 6.0) }, { 3: (35.0, 7.0), 4: (40.0, 5.0) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.084, self.calculator.match_quality(teams, game_info)) self.assertRating(29.698, 7.008, new_ratings.rating_by_id(1)) self.assertRating(30.455, 5.594, new_ratings.rating_by_id(2)) self.assertRating(27.575, 6.346, new_ratings.rating_by_id(3)) self.assertRating(36.211, 4.768, new_ratings.rating_by_id(4))
def new_ratings(self, teams, game_info=None): game_info = EloGameInfo.ensure_game_info(game_info) self.validate_team_and_player_counts(teams) # ensure sorted by rank teams.sort() winner, winner_rating = teams[0].player_rating()[0] loser, loser_rating = teams[1].player_rating()[0] return Match([Team({winner: self.new_rating(winner_rating, loser_rating, teams.comparison(0, 1), game_info)}), Team({loser: self.new_rating(loser_rating, winner_rating, teams.comparison(1, 0), game_info)})])
def test_one_on_two_balanced_partial_play(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { (2, 0.5): (25.0, 25.0 / 3), (3, 0.5): (25.0, 25.0 / 3) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.4472135955, self.calculator.match_quality(teams, game_info)) self.assertRating(30.1102397877, 6.73461146087, new_ratings.rating_by_id(1)) self.assertRating(22.4448801061, 7.96412515904, new_ratings.rating_by_id(2)) self.assertRating(22.4448801061, 7.96412515904, new_ratings.rating_by_id(3))
def test_three_on_two(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (28.0, 7.0), 2: (27.0, 6.0), 3: (26.0, 5.0) }, { 4: (30.0, 4.0), 5: (31.0, 3.0) }], rank=[1, 2]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.254, self.calculator.match_quality(teams, game_info)) self.assertRating(28.658, 6.770, new_ratings.rating_by_id(1)) self.assertRating(27.484, 5.856, new_ratings.rating_by_id(2)) self.assertRating(26.336, 4.917, new_ratings.rating_by_id(3)) self.assertRating(29.785, 3.958, new_ratings.rating_by_id(4)) self.assertRating(30.879, 2.983, new_ratings.rating_by_id(5))
def test_three_teams_of_one_not_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }], rank=[1, 2, 3]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.200, self.calculator.match_quality(teams, game_info)) self.assertRating(31.675352419172107, 6.6559853776206905, new_ratings.rating_by_id(1)) self.assertRating(25.000000000003912, 6.2078966412243233, new_ratings.rating_by_id(2)) self.assertRating(18.324647580823971, 6.6559853776218318, new_ratings.rating_by_id(3))
def test_four_teams_of_one_not_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }, { 4: (25.0, 25.0 / 3) }], rank=[1, 2, 3, 4]) new_ratings = self.calculator.new_ratings(teams, game_info) self.assertMatchQuality( 0.089, self.calculator.match_quality(teams, game_info)) self.assertRating(33.206680965631264, 6.3481091698077057, new_ratings.rating_by_id(1)) self.assertRating(27.401454693843323, 5.7871629348447584, new_ratings.rating_by_id(2)) self.assertRating(22.598545306188374, 5.7871629348413451, new_ratings.rating_by_id(3)) self.assertRating(16.793319034361271, 6.3481091698144967, new_ratings.rating_by_id(4))
def new_ratings(self, matches, rating_period=None, game_info=None): game_info = GlickoGameInfo.ensure_game_info(game_info) # get unique list of players and ensure ratings are consistant players = {} opponents = defaultdict(list) player_rd = {} # Step 1: calculate r and RD for onset of rating period # also cache values of g(RDj) and E(s|r, rj, RDj) for each player for match in matches: # ensure winning team is team 0 match.sort() for player, rating in match.player_rating(): if player in players: if rating != players[player]: raise ValueError( "Inconsistant ratings: player %s has rating %s and rating %s" % (player, rating, players[player])) else: # calc new RD from old RD if (self.c_factor is None or rating.last_rating_period is None or rating_period is None): player_rd[player] = rating.stdev else: t = rating_period - rating.last_rating_period if t <= 0: raise ValueError( "Player %s has a last_rating_period equal to the current rating_period" % (player)) player_rd[player] = min( game_info.beta, sqrt(rating.stdev**2 + self.c_factor * t)) players[player] = rating # create opponent lists of players and outcomes player1 = match[0].players()[0] player2 = match[1].players()[0] opponents[player1].append( (player2, GlickoCalculator.score[match.comparison(0, 1)])) opponents[player2].append( (player1, GlickoCalculator.score[match.comparison(1, 0)])) # Step 2: carry out the update calculations for each player separately q = log(10.0) / 400.0 def g(rd): return 1.0 / sqrt(1.0 + 3.0 * q**2.0 * (rd**2.0) / pi**2.0) def E(r, rj, rd_j): return 1.0 / (1.0 + pow(10.0, -g(rd_j) * (r - rj) / 400.0)) def d2(g_rd, e_sr_r_rd): return pow( q**2.0 * sum(g_rd[j]**2.0 * e_sr_r_rd[j] * (1.0 - e_sr_r_rd[j]) for j in range(len(g_rd))), -1.0) new_ratings = Match() for player, rating in players.items(): # cache values of g(RDj) and E(s|r, r, RDj) for each opponent opponent_g_rd = [] opponent_e_sr_r_rd = [] opponent_s = [] for opponent, score in opponents[player]: opponent_g_rd.append(g(player_rd[opponent])) opponent_e_sr_r_rd.append( E(rating.mean, players[opponent].mean, player_rd[opponent])) opponent_s.append(score) # cache value, this form used twice in the paper rd2_d2 = (1.0 / player_rd[player]**2.0 + 1.0 / d2(opponent_g_rd, opponent_e_sr_r_rd)) # new rating value r_new = (rating.mean + q / rd2_d2 * sum(opponent_g_rd[j] * (opponent_s[j] - opponent_e_sr_r_rd[j]) for j in range(len(opponent_s)))) # new rating deviation value rd_new = sqrt(pow(rd2_d2, -1)) new_ratings.append( Team({player: GlickoRating(r_new, rd_new, rating_period)})) return new_ratings
def test_sixteen_teams_of_one_not_drawn(self): game_info = TrueSkillGameInfo() teams = Match([{ 1: (25.0, 25.0 / 3) }, { 2: (25.0, 25.0 / 3) }, { 3: (25.0, 25.0 / 3) }, { 4: (25.0, 25.0 / 3) }, { 5: (25.0, 25.0 / 3) }, { 6: (25.0, 25.0 / 3) }, { 7: (25.0, 25.0 / 3) }, { 8: (25.0, 25.0 / 3) }, { 9: (25.0, 25.0 / 3) }, { 10: (25.0, 25.0 / 3) }, { 11: (25.0, 25.0 / 3) }, { 12: (25.0, 25.0 / 3) }, { 13: (25.0, 25.0 / 3) }, { 14: (25.0, 25.0 / 3) }, { 15: (25.0, 25.0 / 3) }, { 16: (25.0, 25.0 / 3) }], rank=list(range(16))) new_ratings = self.calculator.new_ratings(teams, game_info) # naive matrix implementation too slow with 16 teams if not hasattr(Matrix, 'is_square'): self.assertMatchQuality( 0.000, self.calculator.match_quality(teams, game_info)) self.assertRating(40.53945776946920, 5.27581643889050, new_ratings.rating_by_id(1)) self.assertRating(36.80951229454210, 4.71121217610266, new_ratings.rating_by_id(2)) self.assertRating(34.34726355544460, 4.52440328139991, new_ratings.rating_by_id(3)) self.assertRating(32.33614722608720, 4.43258628279632, new_ratings.rating_by_id(4)) self.assertRating(30.55048814671730, 4.38010805034365, new_ratings.rating_by_id(5)) self.assertRating(28.89277312234790, 4.34859291776483, new_ratings.rating_by_id(6)) self.assertRating(27.30952161972210, 4.33037679041216, new_ratings.rating_by_id(7)) self.assertRating(25.76571046519540, 4.32197078088701, new_ratings.rating_by_id(8)) self.assertRating(24.23428953480470, 4.32197078088703, new_ratings.rating_by_id(9)) self.assertRating(22.69047838027800, 4.33037679041219, new_ratings.rating_by_id(10)) self.assertRating(21.10722687765220, 4.34859291776488, new_ratings.rating_by_id(11)) self.assertRating(19.44951185328290, 4.38010805034375, new_ratings.rating_by_id(12)) self.assertRating(17.66385277391300, 4.43258628279643, new_ratings.rating_by_id(13)) self.assertRating(15.65273644455550, 4.52440328139996, new_ratings.rating_by_id(14)) self.assertRating(13.19048770545810, 4.71121217610273, new_ratings.rating_by_id(15)) self.assertRating(9.46054223053080, 5.27581643889032, new_ratings.rating_by_id(16))
def new_ratings(self, matches, rating_period=None, game_info=None): game_info = GlickoGameInfo.ensure_game_info(game_info) # get unique list of players and ensure ratings are consistant players = {} opponents = defaultdict(list) player_rd = {} # Step 1: calculate r and RD for onset of rating period # also cache values of g(RDj) and E(s|r, rj, RDj) for each player for match in matches: # ensure winning team is team 0 match.sort() for player, rating in match.player_rating(): if player in players: if rating != players[player]: raise ValueError("Inconsistant ratings: player %s has rating %s and rating %s" % (player, rating, players[player])) else: # calc new RD from old RD if (self.c_factor is None or rating.last_rating_period is None or rating_period is None): player_rd[player] = rating.stdev else: t = rating_period - rating.last_rating_period if t <= 0: raise ValueError("Player %s has a last_rating_period equal to the current rating_period" % (player)) player_rd[player] = min(game_info.beta, sqrt(rating.stdev ** 2 + self.c_factor * t)) players[player] = rating # create opponent lists of players and outcomes player1 = match[0].players()[0] player2 = match[1].players()[0] opponents[player1].append((player2, GlickoCalculator.score[match.comparison(0, 1)])) opponents[player2].append((player1, GlickoCalculator.score[match.comparison(1, 0)])) # Step 2: carry out the update calculations for each player separately q = log(10.0) / 400.0 def g(rd): return 1.0 / sqrt(1.0 + 3.0 * q ** 2.0 * (rd ** 2.0) / pi ** 2.0) def E(r, rj, rd_j): return 1.0 / (1.0 + pow(10.0, -g(rd_j) * (r - rj) / 400.0)) def d2(g_rd, e_sr_r_rd): return pow(q ** 2.0 * sum( g_rd[j] ** 2.0 * e_sr_r_rd[j] * (1.0 - e_sr_r_rd[j]) for j in range(len(g_rd)) ), -1.0) new_ratings = Match() for player, rating in players.items(): # cache values of g(RDj) and E(s|r, r, RDj) for each opponent opponent_g_rd = [] opponent_e_sr_r_rd = [] opponent_s = [] for opponent, score in opponents[player]: opponent_g_rd.append(g(player_rd[opponent])) opponent_e_sr_r_rd.append(E(rating.mean, players[opponent].mean, player_rd[opponent])) opponent_s.append(score) # cache value, this form used twice in the paper rd2_d2 = (1.0 / player_rd[player] ** 2.0 + 1.0 / d2(opponent_g_rd, opponent_e_sr_r_rd)) # new rating value r_new = (rating.mean + q / rd2_d2 * sum( opponent_g_rd[j] * (opponent_s[j] - opponent_e_sr_r_rd[j]) for j in range(len(opponent_s)) )) # new rating deviation value rd_new = sqrt(pow(rd2_d2, -1)) new_ratings.append(Team({player: GlickoRating(r_new, rd_new, rating_period)})) return new_ratings