expected_result=lambda DeltaH: 1/(10**(-DeltaH/400)+1),
probs_from_E=lambda E: [1-E-np.exp(-(E-.5)**2/2/.28**2)/3/2,np.exp(-(E-.5)**2/2/.28**2)/3,E-np.exp(-(E-.5)**2/2/.28**2)/3/2]):
self.probs_from_E = probs_from_E
self.homefield_adv = homefield_adv
self.__expected_result__ = expected_result
# Compute elo from past results
self.score_rate[team] = goals_scored[team]/numRounds
self.concede_rate[team] = goals_conceded[team]/numRounds
for result in past_results:
G = (abs(result["hg"]-result["ag"])+11)/8
W = 1 if result["hg"]>result["ag"] else 0 if result["hg"]<result["ag"] else .5
Wh = self.expected_result(result["ht"],result["at"])
self.elo[result["ht"]].append(self.elo[result["ht"]][-1]+self.weight(result["round"])*G*(W-Wh))
self.elo[result["at"]].append(self.elo[result["at"]][-1]+self.weight(result["round"])*G*(1-W-Wa))
# compute adjusted elo diff with homefield advantage
def elo_diff(self,teamH,teamA):
return self.elo[teamH][-1] - self.elo[teamA][-1] + self.homefield_adv
# compute expected result using supplied formula
def expected_result(self,teamA,teamB):
return self.__expected_result__(self.elo_diff(teamA,teamB))
# compute winning probabilities from expected result and supplied formula
def probabilities(self,teamA,teamB):
E = self.expected_result(teamA,teamB)
return self.probs_from_E(E)
def plot_elo_history(self):
plt.figure(num=None, figsize=(10, 8), facecolor='w', edgecolor='k')
for team, elos in self.elo.items():
plt.plot(elos,label=team)
# compute probability of advancing to the next round from sampling
def advProb(self,nSample=1000):
self.points_after = copy.copy(points)
for match in remaining_matches:
self.match_results[match] = np.random.choice([0,1,3], nSample, p=self.probabilities(match[0],match[1]))
match_resultsA = copy.copy(self.match_results[match])
match_resultsA[match_resultsA == 3] = -1
match_resultsA[match_resultsA == 0] = 3
match_resultsA[match_resultsA == -1] = 0
self.points_after[match[0]] += self.match_results[match]
self.points_after[match[1]] += match_resultsA
# Count number of samples where each team is in the top six
# Rule for equal points: sort teams by goals from past games
self.numTopSix = {team: 0 for team in teams}
points_temp = {team: [self.points_after[team][k],goals[team]] for team in teams}
for team in sorted(points_temp, key=points_temp.get, reverse=True)[:6]:
self.numTopSix[team] += 1
orderedTeams = sorted(self.numTopSix, key=lambda x: self.numTopSix[x],reverse=True)
return {team: self.numTopSix[team]/nSample for team in orderedTeams}
def advProbPois(self,nSample=1000):
self.points_after = copy.copy(points)
self.goals = copy.copy(goals)
for match in remaining_matches:
goalsA = np.random.poisson(lam=(self.score_rate[match[0]]+self.concede_rate[match[1]])/2,size=nSample)
goalsB = np.random.poisson(lam=(self.score_rate[match[1]]+self.concede_rate[match[0]])/2,size=nSample)
self.goals[match[0]] += goalsA
self.goals[match[1]] += goalsB
self.points_after[match[0]] += np.array([3 if gA>gB else 0 if gA<gB else 1 for (gA,gB) in zip(goalsA.tolist(),goalsB.tolist())])
self.points_after[match[1]] += np.array([0 if gA>gB else 3 if gA<gB else 1 for (gA,gB) in zip(goalsA.tolist(),goalsB.tolist())])
self.numTopSix = {team: 0 for team in teams}
points_temp = {team: [self.points_after[team][k],self.goals[team][k]] for team in teams}
for team in sorted(points_temp, key=points_temp.get, reverse=True)[:6]:
self.numTopSix[team] += 1
orderedTeams = sorted(self.numTopSix, key=lambda x: self.numTopSix[x],reverse=True)
return {team: self.numTopSix[team]/nSample for team in orderedTeams}
# plot advancing probabilities
def plot_adv_prob(self,nSample=1000,method="elo"):
probs=self.advProb(nSample=nSample)
probs=self.advProbPois(nSample=nSample)
plt.figure(num=None, figsize=(10, 8), facecolor='w', edgecolor='k')
plt.xticks(rotation='vertical')
plt.bar(probs.keys(),probs.values())
plt.text(x = i-.72 , y = list(probs.values())[i]+.01, s = "{:10.3f}".format(list(probs.values())[i]), size = 12,color="red")