Spaces:
Build error
Build error
import os.path | |
from operator import itemgetter | |
from typing import Text, Tuple | |
import numpy as np | |
import pandas as pd | |
import requests | |
from configs.config import cfg | |
from configs.constants import DATA_ROOT | |
from ml.model import MLModel | |
from ml.utils import load_pickle | |
from datetime import tzinfo, timedelta, datetime | |
ZERO = timedelta(0) | |
class UTC(tzinfo): | |
def utcoffset(self, dt): | |
return ZERO | |
def tzname(self, dt): | |
return "UTC" | |
def dst(self, dt): | |
return ZERO | |
class Predictor: | |
""" | |
A match predictor using ML | |
""" | |
def __init__(self, base_df: pd.DataFrame, model: MLModel): | |
self.model = model | |
self.base_df = base_df | |
def find_stats(self, team): | |
""" | |
:param team: Name of the team, eg: Qatar, etc. | |
:return: | |
""" | |
last_game = self.base_df[(self.base_df["home_team"] == team) | (self.base_df["away_team"] == team)].tail(1) | |
if last_game["home_team"].values[0] == team: | |
team_rank = last_game["rank_home"].values[0] | |
team_goals = last_game["home_goals_mean"].values[0] | |
team_goals_l5 = last_game["home_goals_mean_l5"].values[0] | |
team_goals_suf = last_game["home_goals_suf_mean"].values[0] | |
team_goals_suf_l5 = last_game["home_goals_suf_mean_l5"].values[0] | |
team_rank_suf = last_game["home_rank_mean"].values[0] | |
team_rank_suf_l5 = last_game["home_rank_mean_l5"].values[0] | |
team_gp_rank = last_game["home_game_points_rank_mean"].values[0] | |
team_gp_rank_l5 = last_game["home_game_points_rank_mean_l5"].values[0] | |
else: | |
team_rank = last_game["rank_away"].values[0] | |
team_goals = last_game["away_goals_mean"].values[0] | |
team_goals_l5 = last_game["away_goals_mean_l5"].values[0] | |
team_goals_suf = last_game["away_goals_suf_mean"].values[0] | |
team_goals_suf_l5 = last_game["away_goals_suf_mean_l5"].values[0] | |
team_rank_suf = last_game["away_rank_mean"].values[0] | |
team_rank_suf_l5 = last_game["away_rank_mean_l5"].values[0] | |
team_gp_rank = last_game["away_game_points_rank_mean"].values[0] | |
team_gp_rank_l5 = last_game["away_game_points_rank_mean_l5"].values[0] | |
return [team_rank, team_goals, team_goals_l5, team_goals_suf, team_goals_suf_l5, team_rank_suf, | |
team_rank_suf_l5, team_gp_rank, team_gp_rank_l5] | |
def find_features(team_1, team_2): | |
""" | |
:param team_1: | |
:param team_2: | |
:return: | |
""" | |
rank_dif = team_1[0] - team_2[0] | |
goals_dif = team_1[1] - team_2[1] | |
goals_dif_l5 = team_1[2] - team_2[2] | |
goals_suf_dif = team_1[3] - team_2[3] | |
goals_suf_dif_l5 = team_1[4] - team_2[4] | |
goals_per_ranking_dif = (team_1[1] / team_1[5]) - (team_2[1] / team_2[5]) | |
dif_rank_agst = team_1[5] - team_2[5] | |
dif_rank_agst_l5 = team_1[6] - team_2[6] | |
dif_gp_rank = team_1[7] - team_2[7] | |
dif_gp_rank_l5 = team_1[8] - team_2[8] | |
return [rank_dif, goals_dif, goals_dif_l5, goals_suf_dif, goals_suf_dif_l5, goals_per_ranking_dif, | |
dif_rank_agst, dif_rank_agst_l5, dif_gp_rank, dif_gp_rank_l5, 1, 0] | |
def __predict(self, team_1: Text, team_2: Text): | |
team_1_stat = self.find_stats(team_1) | |
team_2_stat = self.find_stats(team_2) | |
features_g1 = self.find_features(team_1_stat, team_2_stat) | |
features_g2 = self.find_features(team_2_stat, team_1_stat) | |
probs_g1 = self.model.predict_proba([features_g1]) | |
probs_g2 = self.model.predict_proba([features_g2]) | |
team_1_prob_g1 = probs_g1[0][0] | |
team_1_prob_g2 = probs_g2[0][1] | |
team_2_prob_g1 = probs_g1[0][1] | |
team_2_prob_g2 = probs_g2[0][0] | |
team_1_prob = (probs_g1[0][0] + probs_g2[0][1]) / 2 | |
team_2_prob = (probs_g2[0][0] + probs_g1[0][1]) / 2 | |
return team_1_prob_g1, team_1_prob_g2, team_1_prob, team_2_prob, team_2_prob_g1, team_2_prob_g2 | |
def predict(self, team_1: Text, team_2: Text) -> Tuple[bool, Text, float]: | |
""" | |
:param team_1: | |
:param team_2: | |
:return: | |
""" | |
draw = False | |
team_1_prob_g1, team_1_prob_g2, team_1_prob, team_2_prob, team_2_prob_g1, team_2_prob_g2 = self.__predict( | |
team_1, team_2) | |
winner, winner_proba = "", 0.0 | |
if ((team_1_prob_g1 > team_2_prob_g1) & (team_2_prob_g2 > team_1_prob_g2)) | ( | |
(team_1_prob_g1 < team_2_prob_g1) & (team_2_prob_g2 < team_1_prob_g2)): | |
draw = True | |
elif team_1_prob > team_2_prob: | |
winner = team_1 | |
winner_proba = team_1_prob | |
elif team_2_prob > team_1_prob: | |
winner = team_2 | |
winner_proba = team_2_prob | |
return draw, winner, winner_proba | |
def predict_all_matches(self) -> Text: | |
""" | |
Predict all the matches in the tournament | |
:return: | |
""" | |
result = "" | |
data = load_pickle(os.path.join(DATA_ROOT, cfg.data.table_matches)) | |
table = data['table'] | |
matches = data['matches'] | |
advanced_group, last_group = [], "" | |
for teams in matches: | |
draw = False | |
team_1_prob_g1, team_1_prob_g2, team_1_prob, team_2_prob, team_2_prob_g1, team_2_prob_g2 = self.__predict( | |
teams[1], teams[2]) | |
winner, winner_proba = "", 0.0 | |
if ((team_1_prob_g1 > team_2_prob_g1) & (team_2_prob_g2 > team_1_prob_g2)) | ( | |
(team_1_prob_g1 < team_2_prob_g1) & (team_2_prob_g2 < team_1_prob_g2)): | |
draw = True | |
for i in table[teams[0]]: | |
if i[0] == teams[1] or i[0] == teams[2]: | |
i[1] += 1 | |
elif team_1_prob > team_2_prob: | |
winner = teams[1] | |
winner_proba = team_1_prob | |
for i in table[teams[0]]: | |
if i[0] == teams[1]: | |
i[1] += 3 | |
elif team_2_prob > team_1_prob: | |
winner = teams[2] | |
winner_proba = team_2_prob | |
for i in table[teams[0]]: | |
if i[0] == teams[2]: | |
i[1] += 3 | |
for i in table[teams[0]]: # adding tiebreaker (probs per game) | |
if i[0] == teams[1]: | |
i[2].append(team_1_prob) | |
if i[0] == teams[2]: | |
i[2].append(team_2_prob) | |
if last_group != teams[0]: | |
if last_group != "": | |
result += "\n" | |
result += "Group %s advanced: \n" % last_group | |
for i in table[last_group]: # adding tiebreaker | |
i[2] = np.mean(i[2]) | |
final_points = table[last_group] | |
final_table = sorted(final_points, key=itemgetter(1, 2), reverse=True) | |
advanced_group.append([final_table[0][0], final_table[1][0]]) | |
for i in final_table: | |
result += "%s -------- %d\n" % (i[0], i[1]) | |
result += "\n" | |
result += "-" * 10 + " Starting Analysis for Group %s " % (teams[0]) + "-" * 10 + "\n" | |
if draw is False: | |
result += "Group %s - %s vs. %s: Winner %s with %.2f probability\n" % ( | |
teams[0], teams[1], teams[2], winner, winner_proba) | |
else: | |
result += "Group %s - %s vs. %s: Draw\n" % (teams[0], teams[1], teams[2]) | |
last_group = teams[0] | |
result += "\n" | |
result += "Group %s advanced: \n" % last_group | |
for i in table[last_group]: # adding tiebreaker | |
i[2] = np.mean(i[2]) | |
final_points = table[last_group] | |
final_table = sorted(final_points, key=itemgetter(1, 2), reverse=True) | |
advanced_group.append([final_table[0][0], final_table[1][0]]) | |
for i in final_table: | |
result += "%s -------- %d\n" % (i[0], i[1]) | |
advanced = advanced_group | |
playoffs = {"Round of 16": [], "Quarter-Final": [], "Semi-Final": [], "Final": []} | |
for p in playoffs.keys(): | |
playoffs[p] = [] | |
actual_round = "" | |
next_rounds = [] | |
for p in playoffs.keys(): | |
if p == "Round of 16": | |
control = [] | |
for a in range(0, len(advanced * 2), 1): | |
if a < len(advanced): | |
if a % 2 == 0: | |
control.append((advanced * 2)[a][0]) | |
else: | |
control.append((advanced * 2)[a][1]) | |
else: | |
if a % 2 == 0: | |
control.append((advanced * 2)[a][1]) | |
else: | |
control.append((advanced * 2)[a][0]) | |
playoffs[p] = [[control[c], control[c + 1]] for c in range(0, len(control) - 1, 1) if c % 2 == 0] | |
for i in range(0, len(playoffs[p]), 1): | |
game = playoffs[p][i] | |
home = game[0] | |
away = game[1] | |
team_1_prob_g1, team_1_prob_g2, team_1_prob, team_2_prob, team_2_prob_g1, team_2_prob_g2 = \ | |
self.__predict(home, away) | |
if actual_round != p: | |
result += "-" * 10 + "\n" | |
result += "Starting simulation of %s\n" % p | |
result += "-" * 10 + "\n" | |
if team_1_prob < team_2_prob: | |
result += "%s vs. %s: %s advances with prob %.2f\n" % (home, away, away, team_2_prob) | |
next_rounds.append(away) | |
else: | |
result += "%s vs. %s: %s advances with prob %.2f\n" % (home, away, home, team_1_prob) | |
next_rounds.append(home) | |
game.append([team_1_prob, team_2_prob]) | |
playoffs[p][i] = game | |
actual_round = p | |
else: | |
playoffs[p] = [[next_rounds[c], next_rounds[c + 1]] for c in range(0, len(next_rounds) - 1, 1) if | |
c % 2 == 0] | |
next_rounds = [] | |
for i in range(0, len(playoffs[p])): | |
game = playoffs[p][i] | |
home = game[0] | |
away = game[1] | |
team_1_prob_g1, team_1_prob_g2, team_1_prob, team_2_prob, team_2_prob_g1, team_2_prob_g2 = \ | |
self.__predict(home, away) | |
if actual_round != p: | |
result += "-" * 10 + "\n" | |
result += "Starting simulation of %s\n" % p | |
result += "-" * 10 + "\n" | |
if team_1_prob < team_2_prob: | |
result += "%s vs. %s: %s advances with prob %.2f \n" % (home, away, away, team_2_prob) | |
next_rounds.append(away) | |
else: | |
result += "%s vs. %s: %s advances with prob %.2f \n" % (home, away, home, team_1_prob) | |
next_rounds.append(home) | |
game.append([team_1_prob, team_2_prob]) | |
playoffs[p][i] = game | |
actual_round = p | |
print(result) | |
return result | |