사용자 도구

사이트 도구


elo

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

다음 판
이전 판
elo [2018/02/27 13:49] – 만듦 rex8312elo [2024/05/08 13:34] (현재) rex8312
줄 1: 줄 1:
 ======= Elo ======= ======= Elo =======
 +
 +
 +<code python>
 +
 +import random
 +import collections
 +import math
 +
 +import numpy as np
 +import matplotlib.pyplot as plt
 +from IPython import embed
 +
 +
 +def k_factor(player):
 +    """
 +    player의 k factor 계산
 +    """
 +    if player.elo < 1100:
 +        return 25
 +    elif player.elo < 2400:
 +        return 15
 +    else:
 +        return 10
 +
 +
 +def expected_score(player: float, opponent: float):
 +    """
 +    player와 opponent와 게임에서 얻을 수 있는 기대 점수(승률)
 +
 +    :param player: player의 Elo
 +    :param opponent: opponent의 Elo
 +    """
 +    return 1 / (1 + 10 ** ((opponent - player) / 400))
 +
 +
 +def elo(old_elo, true_score, exp_score, k):
 +    """
 +    player의 새로운 Elo 값 계산
 +
 +    :param old_elo: 이전 Elo
 +    :param true_score: player의 실제 점수
 +    :param exp_score: player의 기대 점수
 +    :param k: k-factor
 +    """
 +    return old_elo + k * (true_score - exp_score)
 +
 +
 +def play_game(player1, player2, n_games=1):
 +    score1 = player1.play()
 +    score2 = player2.play()
 +
 +    player1_score = 0.0
 +    player2_score = 0.0
 +
 +    for _ in range(n_games):
 +        if score1 > score2:
 +            player1_score += 1.0
 +            player2_score += 0.0
 +        elif score1 < score2:
 +            player1_score += 0.0
 +            player2_score += 1.0
 +        elif math.isclose(score1, score2):
 +            player1_score += 0.5
 +            player2_score += 0.5
 +
 +    player1_score /= n_games
 +    player2_score /= n_games
 +
 +    player1_exp_score = expected_score(player1.elo, player2.elo)
 +    player1_k = k_factor(player1)
 +    player1.elo = elo(player1.elo, player1_score, player1_exp_score, player1_k)
 +
 +    player2_exp_score = expected_score(player2.elo, player1.elo)
 +    player2_k = k_factor(player2)
 +    player2.elo = elo(player2.elo, player2_score, player2_exp_score, player2_k)
 +    return player1, player2
 +
 +
 +def match_make(players):
 +    return random.sample(players, 2)
 +
 +
 +class Player:
 +    def __init__(self, name, performance, init_elo=1000):
 +        self.name = name
 +        self._performance = performance
 +        self.elo = init_elo
 +
 +    def play(self):
 +        # 정규 분포보다, 균등분포가 Elo가 크게 벌어짐
 +        # return random.random() + self._performance
 +
 +        # std가 커질 수록 구분이 어려움
 +        return random.gauss(self._performance, 1.0)
 +
 +    def __repr__(self):
 +        return f'{self.name}: {self._performance}, {int(self.elo):d}'
 +
 +
 +def moving_average(xs, window_size=3):
 +    assert len(xs) > 0
 +    assert window_size > 0
 +
 +    if window_size % 2 == 0:
 +        window_size += 1
 +
 +    if window_size > 1 and len(xs) > window_size:
 +        weights = np.ones(window_size) / window_size
 +        xs_extended = [xs]
 +        for _ in range(window_size // 2):
 +            xs_extended.insert(0, xs[:1])
 +            xs_extended.insert(-1, xs[-1:])
 +        xs_extended = np.concatenate(xs_extended)
 +        return np.convolve(xs_extended, weights, mode='valid')
 +    else:
 +        return xs
 +
 +
 +if __name__ == '__main__':
 +
 +    max_games = 100000
 +    n_game_per_iter = 10
 +    players = [Player('A', 1, init_elo=1200),
 +               Player('B', 0.5), Player('C', 0.45), Player('D', 0.40), Player('E', 0.30)]
 +    records = collections.deque(maxlen=max_games // n_game_per_iter)
 +
 +    for n_games in range(max_games // n_game_per_iter):
 +        player1, player2 = match_make(players)
 +        play_game(player1, player2, n_game_per_iter)
 +        records.append([p.elo for p in players])
 +
 +    for player, elo_records in zip(players, zip(*records)):
 +        elo_records = moving_average(elo_records, 100)
 +        plt.plot(elo_records, label=player.name)
 +
 +    plt.legend()
 +    plt.show()
 +
 +    # embed()
 +
 +</code>
 +
 +===== 참고 =====
  
   * https://github.com/rshk/elo/blob/master/elo.py   * https://github.com/rshk/elo/blob/master/elo.py
 +  * https://github.com/djcunningham0/multielo
 +  * [[trueskill|Trueskill]]
elo.1519739370.txt.gz · 마지막으로 수정됨: (바깥 편집)