Last active
January 17, 2018 14:34
-
-
Save adrialuzllompart/2d1063596ba5c25e379c109d86b4ee5a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from __future__ import division | |
import numpy as np | |
import pandas as pd | |
import random | |
from datetime import date | |
def expected(A, B): | |
""" | |
Calculate expected score of team A in a match against team B | |
parameters | |
------------------------- | |
A: float | |
Elo rating for team A | |
B: float | |
Elo rating for team B | |
""" | |
return 1 / (1 + 10 ** ((B - A) / 400)) | |
def elo(old, exp, score, k=32): | |
""" | |
Calculate the new Elo rating for the players in a given team | |
parameters | |
-------------------------- | |
old: float | |
The previous Elo rating | |
exp: float | |
The expected probability of winning for this match | |
score: int | |
The actual score for this match (1 for win, 0 for loss) | |
k: int | |
The k-factor for Elo (default: 32) | |
""" | |
return old + k * (score - exp) | |
# read in the latest data | |
filename = 'C:/Users/aluz/Desktop/elo_football/elo_football.csv' | |
df = pd.read_csv(filename) | |
# have the teams already been selected? | |
x = raw_input('Have the teams already been selected (y or n)? >') | |
# if they have... | |
if x == 'y': | |
# input the names of the players who play for team 1 | |
team_1_str = raw_input('Players in team 1 (separate with a comma) >') | |
# and convert that string to a list where each item is a player of team 1 | |
team_1 = team_1_str.split(',') | |
# input the names of the players who play for team 2 | |
team_2_str = raw_input('Players in team 2 (separate with a comma) >') | |
# and convert that string to a list where each item is a player of team 2 | |
team_2 = team_2_str.split(',') | |
# calculate the team ratings by adding up the individual ratings of the players in each team | |
team_1_ratings = df.loc[df.player.isin(team_1), 'rating'].sum() | |
team_2_ratings = df.loc[df.player.isin(team_2), 'rating'].sum() | |
# calculate the expected probabilities of winning for each team, | |
# according to the Elo expected function defined above | |
exp_1 = expected(team_1_ratings, team_2_ratings) | |
exp_2 = 1 - exp_1 | |
# print the probability of winning for team 1, as well as what players are playing in each team | |
print 'Probability of team 1 winning = ', exp_1 | |
print 'Team 1: ', team_1 | |
print 'Team 2: ', team_2 | |
# if the teams haven't been selected yet... | |
else: | |
# input the names of all the players that are available for the game (8 to 12 players) | |
available = raw_input('List of players that are playing today (separate with a comma) >') | |
# and convert that string to a list where each item is a player | |
available_list = available.split(',') | |
# calculate the number of players in team 1 | |
# if the length of the list is an even number, n will be equal to the number of players in each team | |
# if the length of the list is an odd number, n will be equal to the number of players in team 1 | |
# team 2 will have len(available_list) - n players | |
# e.g. if there are 9 players, int(9 / 2) = 4, so team 1 will have 4 players and team 2 will have 5 players | |
n = int(len(available_list) / 2) | |
# initialize an empty list of players for team 1 | |
team_1 = [] | |
# initialize exp and iterations variables | |
exp = 0 | |
iterations = 0 | |
# repeat the following while the teams are not balanced enough | |
# for them to be balanced, the probability of winning for team 1 | |
# has to be between 40 and 60% | |
while (exp <= 0.40) | (exp >= 0.60): | |
# re-create the list of all players every time | |
available_list = available.split(',') | |
team_1 = [] | |
# do this as many times as there are players in team 1 | |
for i in range(n): | |
# select a random player from the whole list of players available | |
name = random.choice(available_list) | |
# add that name to team 1 | |
team_1.append(name) | |
# remove that name from the list to ensure we don't draw it again | |
available_list.remove(name) | |
# team 2 will be formed by all the players available that are not in team 1 | |
team_2 = [player for player in available.split(',') if player not in team_1] | |
# calculate the ratings for each team, based on this random split | |
team_1_ratings = df.loc[df.player.isin(team_1), 'rating'].sum() | |
team_2_ratings = df.loc[df.player.isin(team_2), 'rating'].sum() | |
# calculate the expected probability of winning for team 1 | |
# if this is not between 40 and 60%, the loop will run again | |
exp = expected(team_1_ratings, team_2_ratings) | |
iterations += 1 | |
# set the final expectations of winning for each team | |
exp_1 = exp | |
exp_2 = 1 - exp_1 | |
# print how many iterations it took the while loop to find a balanced match | |
# as well as the expected probability of winning for team 1 | |
# and who's in each team | |
print iterations | |
print 'Probability of team 1 winning = ', exp_1 | |
print 'Team 1: ', team_1 | |
print 'Team 2: ', team_2 | |
# after the game, input the number of the team that won the match | |
winning_team = raw_input('Who won? 1 or 2? >') | |
# if team 1 won, set their score to 1 and team 2's score to 0, and viceversa | |
if winning_team == '1': | |
score_1 = 1 | |
score_2 = 0 | |
else: | |
score_1 = 0 | |
score_2 = 1 | |
# calculate the difference between the current team rating and the new Elo rating | |
# based on the elo function defined above | |
diff_1 = elo(team_1_ratings, exp_1, score_1) - team_1_ratings | |
diff_2 = elo(team_2_ratings, exp_2, score_2) - team_2_ratings | |
# create a copy of the original table | |
df_new = df.copy() | |
# adjust the ratings of each player based on whether they won or lost | |
# the adjustment is the difference calculated above | |
df_new.loc[df_new.player.isin(team_1), 'rating'] += diff_1 | |
df_new.loc[df_new.player.isin(team_2), 'rating'] += diff_2 | |
# overwrite the original file with the new file, which has the adjusted player ratings | |
df_new.to_csv(filename, index=False) | |
# read in the historical data | |
filename_hist = 'C:/Users/aluz/Desktop/elo_football/elo_football_history.csv' | |
df_hist = pd.read_csv(filename_hist) | |
# format the date properly | |
df_hist.date = pd.to_datetime(df_hist.date, format='%d/%m/%Y') | |
# add the new (most up-to-date) ratings to the historical ones | |
df_hist_expanded = pd.concat([df_hist, df_new], axis=0) | |
# add today's date as the date for the new ratings | |
# we want to add the dates so in the future we will be able to plot the ratings over time | |
df_hist_expanded.date.fillna(date.today(), inplace=True) | |
# save the historical data | |
df_hist_expanded.to_csv(filename_hist, index=False) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment