
Elo
Elo评分系统Elo rating system)是一种用于评估玩家或团队相对技能水平的评分系统,最初由匈牙利裔美国物理学家和统计学家阿尔帕德·埃洛(Arpad Elo)为国际象棋设计。如今,Elo评分系统被广泛应用于各种竞技游戏和体育赛事中,如围棋、电子竞技、足球等。
比如围棋AI Katago训练的神经网络文件的评分:
使用Elo评分系统可以根据能力给运动员或玩家评分,用于表示竞技能力,匹配相似竞技能力的人进行比赛。
评分机制
Elo 评分系统的核心概念是根据比赛结果更新玩家的评分。系统会根据比赛双方的当前评分预估比赛结果,然后根据实际结果调整双方的评分。
每个新加入系统的玩家都会被赋予一个初始评分,通常为 1500,但具体数值可以根据不同的系统设定。
2. 期望胜率(Expected Score)


Python代码
import math
def probability(rating1, rating2):
"""
计算 rating1 对 rating2 的胜率
:param rating1: 评分1
:param rating2: 评分2
:return: 胜率
"""
return 1.0 / (1 + math.pow(10, (rating2 - rating1) / 400.0))
def elo_rating(Ra, Rb, outcome, K=30):
"""
根据对战结果,计算新的Elo评分
:param Ra: 玩家A评分
:param Rb: 玩家B评分
:param outcome: 1 玩家A胜,2玩家B胜,0.5 平局
:param K: K值,默认30
:return:
"""
# 计算玩家A,B的胜率
Pa = probability(Ra, Rb)
Pb = probability(Rb, Ra)
# 更新Elo 评分
Ra = Ra + K * (outcome - Pa)
Rb = Rb + K * ((1 - outcome) - Pb)
# 返回
return Ra, Rb
if __name__ == '__main__':
# 当前 ELO 评分
Ra = 1600
Rb = 1400
# 常数 K 值
K = 30
# Outcome: 1 A 胜, 0 A 负, 0.5 平
outcome = 1
# 计算新评分
print(elo_rating(Ra, Rb, outcome, K))
#(1607.2075922005613, 1392.7924077994387)
TrueSkill 由微软研究院开发,它相当于是Elo的升级版,能够处理不同规模的游戏,从一对一到团队对抗。即使是少量比赛,也能快速准确地估计玩家的技能。支持自定义参数以适应不同的游戏规则。它现在Xbox LIVE上用于排名和配对服务。
TrueSkill 评分不只有能力分(μ)还有稳定度(σ)参数,在每次对战后都会进行调节。
安装:
$ pip install trueskill1V1比赛:
from trueskill import Rating, quality_1vs1, rate_1vs1
import time
A = Rating()
B = Rating()
# 默认mu = 25,sigma=8.3
print("A: ",A) # A: trueskill.Rating(mu=25.000, sigma=8.333)
print("B: ",B) # B: trueskill.Rating(mu=25.000, sigma=8.333)
print('匹配度:{:.1%}'.format(quality_1vs1(A, B)))
if quality_1vs1(A, B) < 0.5:
print('匹配不科学')
for i in range(10): # 对战10次
A, B = rate_1vs1(A, B)
print("A: ",A) # A: trueskill.Rating(mu=34.602, sigma=4.947)
print("B: ",B) # B: trueskill.Rating(mu=15.398, sigma=4.947)
Rating()函数用来生成一个评分对象,没有参数将会使用系统默认值(可调),也可带参数生成对象:
Rating(mu=50, sigma=1)quality_1vs1()函数计算平局的概率,用于判断两个人是否匹配,mu值尽量相同,sigma小一些平局概率会增大。
rate_1vs1(A, B) # 代表A战胜B,
rate_1vs1(A, B, drawn=True) # 代表平局,drawn是平局的意思团队赛:
TrueSkill可以对多个团队,每个团队不同人数的比赛进行评分调整:
from trueskill import Rating, quality, rate
r1 = Rating() # 1P's skill
r2 = Rating() # 2P's skill
r3 = Rating() # 3P's skill
t1 = [r1] # Team A contains just 1P
t2 = [r2, r3] # Team B contains 2P and 3P
print('{:.1%} chance to draw'.format(quality([t1, t2])))
(new_r1,), (new_r2, new_r3) = rate([t1, t2], ranks=[0, 1])
print(new_r1)
print(new_r2)
print(new_r3)rate() 函数对比赛进行计分,ranks用来表示队伍的胜负,小的算赢大的算输
[(r1, r2, r3), (r4, r5, r6)][(r1, r2), (r3, r4), (r5, r6)][(r1,), (r2, r3, r4)][(r1,), (r2,), (r3,), (r4,)]部分参与
如果一个团队中某人并没有完整参与比赛,比如迟到了,他只在后半部分加入游戏,称为部分参与(Partial play), 这种情况下需要有个参与的权重(weight)参数。
例如:有两个团队,各有两人参赛,比赛持续一小时。其中第一个队伍的r2队员半小时后才加入比赛,完整参赛的权重为1,参加了一半的为0.5 ,则函数中配置权重为:
quality([(r1, r2), (r3, r4)], weights=[(1, 0.5), (1, 1)])
rate([(r1, r2), (r3, r4)], weights=[(1, 0.5), (1, 1)])也可以用字典来配置,key用元组定位人员,第一位是团队号,第二位是人员编号, 值是权重:
# 设置第一个队伍的第二个队员权重为0.5, 其余人员权重保持为1
rate([(r1, r2), (r3, r4)], weights={(0, 1): 0.5})其实也可以带名字进行比赛评分
# 设置第二个队伍的carol选手权重为0.5, 其余人员权重保持1
rate([{'alice': r1, 'bob': r2}, {'carol': r3}], weights={(1, 'carol'): 0.5})配置
TrueSkill 有很多参数, 如果没有配置会使用全局默认值,如果希望根据自身情况配置需要手动实例化TrueSkill对象, 一般被称为环境配置env.
from trueskill import TrueSkill
env = TrueSkill(mu=50)class trueskill.TrueSkill(
mu=25.0,
sigma=8.333333333333334,
beta=4.166666666666667,
tau=0.08333333333333334,
draw_probability=0.1,
backend=None)注: 关于backend
TrueSkill 内部实现并使用了三种算法:
累积分布函数 cumulative distribution function;
概率密度函数 probability density function;
逆累积分布函数 inverse cumulative distribution function.
第三方专业库比如mpmath,scipy也提供了这些算法, 可以作为backend参数配置使用
env = TrueSkill(backend='mpmath')指定配置生成Rating
>>> env = TrueSkill(mu=0, sigma=1)
>>> env.create_rating()
trueskill.Rating(mu=0.000, sigma=1.000)对Rating排序
用于生成排行榜,比较函数为env.expose()
leaderboard = sorted(ratings, key=env.expose, reverse=True)设置为全局
>>> Rating()
trueskill.Rating(mu=25.000, sigma=8.333)
>>> env = TrueSkill(mu=50)
>>> env.make_as_global()
trueskill.TrueSkill(mu=50.000, ...)
>>> Rating()
trueskill.Rating(mu=50.000, sigma=8.333)指定env计算平均概率
env = TrueSkill()
if env.quality([team1, team2, team3]) < 0.50:
print('This match seems to be not so fair')指定env计算Rating
env = TrueSkill() # uses default settings
# create ratings
r1 = env.create_rating(42.222)
r2 = env.create_rating(89.999)
# calculate new ratings
rating_groups = [(r1,), (r2,)]
rated_rating_groups = env.rate(rating_groups, ranks=[0, 1])
# save new ratings
(r1,), (r2,) = rated_rating_groups全局函数
全局函数除了上文介绍过的还有这么几个
获取全局env:
env = trueskill.global_env()设置全局参数:
>>> trueskill.setup(mu=50)
trueskill.TrueSkill(mu=50.000, ...)
>>> Rating()
trueskill.Rating(mu=50.000, sigma=8.333)全局expose:
trueskill.expose(rating)更多细节详见 https://trueskill.org/