Skip to content

Instantly share code, notes, and snippets.

@paulgrav
Last active August 29, 2015 13:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paulgrav/9393738 to your computer and use it in GitHub Desktop.
Save paulgrav/9393738 to your computer and use it in GitHub Desktop.
Rankings
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import operator
import pprint
matches = [
{ "h": {"name": "PG", "score": 2}, "a": {"name": "MK", "score": 2} },
{ "h": {"name": "PG", "score": 1}, "a": {"name": "MK", "score": 2} },
{ "h": {"name": "MK", "score": 1}, "a": {"name": "PG", "score": 0} },
{ "h": {"name": "GT", "score": 1}, "a": {"name": "MK", "score": 2} },
{ "h": {"name": "NP", "score": 2}, "a": {"name": "MK", "score": 1} },
{ "h": {"name": "PG", "score": 0}, "a": {"name": "MC", "score": 1} },
{ "h": {"name": "PG", "score": 0}, "a": {"name": "JH", "score": 0} },
{ "h": {"name": "PG", "score": 3}, "a": {"name": "CBo", "score": 0} },
{ "h": {"name": "PG", "score": 1}, "a": {"name": "NP", "score": 1} },
{ "h": {"name": "MC", "score": 1}, "a": {"name": "DG", "score": 2} },
{ "h": {"name": "MC", "score": 0}, "a": {"name": "DK", "score": 0} },
{ "h": {"name": "DK", "score": 3}, "a": {"name": "CBo", "score": 0} },
{ "h": {"name": "AB", "score": 0}, "a": {"name": "CBo", "score": 0} },
{ "h": {"name": "CBo", "score": 2}, "a": {"name": "JH", "score": 0} },
{ "h": {"name": "GT", "score": 1}, "a": {"name": "DK", "score": 1} },
{ "h": {"name": "DK", "score": 4}, "a": {"name": "NP", "score": 4} },
{ "h": {"name": "NP", "score": 1}, "a": {"name": "CBe", "score": 1} },
{ "h": {"name": "MK", "score": 1}, "a": {"name": "CBe", "score": 1} },
{ "h": {"name": "AB", "score": 0}, "a": {"name": "PG", "score": 1} },
{ "h": {"name": "JH", "score":1 }, "a": {"name": "CBe", "score": 4} },
{ "h": {"name": "JH", "score":2 }, "a": {"name": "MK", "score": 1} },
{ "h": {"name": "DK", "score":0 }, "a": {"name": "DG", "score": 4} },
{ "h": {"name": "DG", "score":2 }, "a": {"name": "CBo", "score": 0} },
{ "h": {"name": "DK", "score":3 }, "a": {"name": "AB", "score": 0} },
{ "h": {"name": "PG", "score":2 }, "a": {"name": "GT", "score": 0} },
{ "h": {"name": "DG", "score":3 }, "a": {"name": "DK", "score": 1} },
{ "h": {"name": "NP", "score":4 }, "a": {"name": "JH", "score": 0} },
{ "h": {"name": "MC", "score":5 }, "a": {"name": "CBo", "score": 0} },
]
current_ratings = {}
K = 20 # all matches are friendlies
INITIAL_RANKING = 1700
def rating(ro, k, w, we):
return ro + k * (w - we)
def winexpect(dr):
"""
winexpectancy should return a float between 0 and 1.0.
dr is the rating difference
"""
return 1 / (10 ** ( -dr / 400) + 1.0)
def resultscore(scorea, scoreb):
if scorea > scoreb:
return 1
if scorea < scoreb:
return 0
return 0.5
def kmodifier(gd):
#K is then adjusted for the goal difference in the game. It is increased by half if a game is won by two goals, by 3/4 if a game is won by three goals, and by 3/4 + (N-3)/8 if the game is won by four or more goals, where N is the goal difference.
if gd >=4:
return 1.75 + (gd-3)/8
if gd >=3:
return 1.75
if gd >=2:
return 1.5
return 1
def ratingsformatch(match):
hname = match["h"]["name"]
aname = match["a"]["name"]
hscore = match["h"]["score"]
ascore = match["a"]["score"]
chrating = current_ratings.get(hname, INITIAL_RANKING)
carating = current_ratings.get(aname, INITIAL_RANKING)
hres = resultscore(hscore, ascore)
ares = resultscore(ascore, hscore)
goaldiff = abs(hscore - ascore)
hrating = rating(chrating, K * kmodifier(goaldiff), hres, winexpect(chrating - carating))
arating = rating(carating, K * kmodifier(goaldiff), ares, winexpect(carating - chrating))
return (hrating, arating)
for i in matches:
(hrating, arating) = ratingsformatch(i)
hname = i['h']['name']
aname = i['a']['name']
i["h"]["rating"] = int(hrating)
i["a"]["rating"] = int(arating)
current_ratings[hname] = hrating
current_ratings[aname] = arating
sorted_ratings = sorted(current_ratings.iteritems(), key=operator.itemgetter(1))
sorted_ratings.reverse()
for (k, v) in sorted_ratings:
print "%s\t%s" % (k, int(v))
print
for i in matches:
for (k,v) in i.iteritems():
print "%s\t%s\t%s" % (v['name'],v['score'],v['rating'])
# The ratings are based on the following formulas:
#
# Rn = Ro + K x (W - We)
#
# Rn is the new rating, Ro is the old (pre-match) rating.
#
# K is the weight constant for the tournament played:
#
# 60 for World Cup finals;
# 50 for continental championship finals and major intercontinental tournaments;
# 40 for World Cup and continental qualifiers and major tournaments;
# 30 for all other tournaments;
# 20 for friendly matches.
# K is then adjusted for the goal difference in the game. It is increased by half if a game is won by two goals, by 3/4 if a game is won by three goals, and by 3/4 + (N-3)/8 if the game is won by four or more goals, where N is the goal difference.
#
# W is the result of the game (1 for a win, 0.5 for a draw, and 0 for a loss).
#
# We is the expected result (win expectancy), either from the chart or the following formula:
#
# We = 1 / (10(-dr/400) + 1)
#
# dr equals the difference in ratings plus 100 points for a team playing at home.
#
# Sample Winning Expectancies
# Difference
# in Ratings Higher
# Rated Lower
# Rated
# 0 0.500 0.500
# 10 0.514 0.486
# 20 0.529 0.471
# 30 0.543 0.457
# 40 0.557 0.443
# 50 0.571 0.429
# 60 0.585 0.415
# 70 0.599 0.401
# 80 0.613 0.387
# 90 0.627 0.373
# 100 0.640 0.360
# 110 0.653 0.347
# 120 0.666 0.334
# 130 0.679 0.321
# 140 0.691 0.309
# 150 0.703 0.297
# 160 0.715 0.285
# 170 0.727 0.273
# 180 0.738 0.262
# 190 0.749 0.251
# 200 0.760 0.240
# 210 0.770 0.230
# 220 0.780 0.220
# 230 0.790 0.210
# 240 0.799 0.201
# 250 0.808 0.192
# 260 0.817 0.183
# 270 0.826 0.174
# 280 0.834 0.166
# 290 0.841 0.159
# 300 0.849 0.151
# 325 0.867 0.133
# 350 0.882 0.118
# 375 0.896 0.104
# 400 0.909 0.091
# 425 0.920 0.080
# 450 0.930 0.070
# 475 0.939 0.061
# 500 0.947 0.053
# 525 0.954 0.046
# 550 0.960 0.040
# 575 0.965 0.035
# 600 0.969 0.031
# 625 0.973 0.027
# 650 0.977 0.023
# 675 0.980 0.020
# 700 0.983 0.017
# 725 0.985 0.015
# 750 0.987 0.013
# 775 0.989 0.011
# 800 0.990 0.010
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment