def read_predictions(year, week): # Check if the week is 'bowl' week num_weeks = the_kick_is_bad.read_number_of_weeks(year) week, _ = utils.check_week(week, num_weeks) # Open predictions file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/{year}/predictions-{year}-{week:02}.csv" with open(filename) as file: predictions = [] # Remove the header line _ = file.readline().strip() # Loop through lines to read prediction data prediction_line = file.readline().strip() while prediction_line: # Split the prediction data prediction = prediction_line.split(",") away_team = prediction[0] home_team = prediction[1] predicted_winner = prediction[2] predicted_margin_of_victory = prediction[3] game_interest = prediction[4] # Pack prediction structure predictions.append({ "away team": away_team, "home team": home_team, "predicted winner": predicted_winner, "predicted margin of victory": float(predicted_margin_of_victory), "game interest": float(game_interest) }) prediction_line = file.readline().strip() return predictions
def read_rankings(year, week): # Check if the week is 'bowl' week num_weeks = the_kick_is_bad.read_number_of_weeks(year) week, _ = utils.check_week(week, num_weeks) # Open rankings file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/{year}/team_rankings-{year}-{week:02}.csv" with open(filename) as file: rankings = {} # Remove the header line _ = file.readline().strip() # Loop through lines to read ranking data ranking_line = file.readline().strip() while ranking_line: # Split the ranking data ranking = ranking_line.split(",") team = ranking[0] rank = ranking[1] previous_rank = ranking[2] delta_rank = ranking[3] team_score = ranking[4] strength = ranking[5] standard_deviation = ranking[6] # Pack ranking structure rankings[team] = { "rank": int(rank), "previous rank": int(previous_rank), "delta rank": int(delta_rank), "team score": float(team_score), "strength": float(strength), "standard deviation": float(standard_deviation) } ranking_line = file.readline().strip() return rankings
def calculate_division_rankings(year, week, teams, team_rankings): # Make lists of all the team scores in each division division_rankings = {} for team in teams: division = teams[team]["division"] if division not in division_rankings: division_rankings[division] = [] division_rankings[division].append(team_rankings[team]["team score"]) # Convert dictionary to averaged list for sorting sorted_division_rankings = [] for division in division_rankings: sorted_division_rankings.append({ "division": division, "score": statistics.mean(division_rankings[division]) }) # Sort division rankings by average team score sorted_division_rankings = sorted(sorted_division_rankings, key=lambda p: p["score"], reverse=True) # Print division rankings rank = 1 division_rankings_file_string = "Division,Score\n" for division_ranking in sorted_division_rankings: # Print to file string in csv format division = division_ranking["division"] score = division_ranking["score"] division_rankings_file_string += f"{division},{score:.1f}\n" # Print to console in pretty format print(f"{rank}: {division}, Score: {score:.1f}") rank += 1 # Create the division rankings file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/rankings/{year}/division_rankings-{year}-{week:02}.csv" utils.write_string(division_rankings_file_string, filename)
def calculate_conference_rankings(year, week, teams, team_rankings): # Make lists of all the team scores in each conference conference_rankings = {} for team in teams: conference = teams[team]["conference"] if conference not in conference_rankings: conference_rankings[conference] = [] conference_rankings[conference].append(team_rankings[team]["team score"]) # Convert dictionary to averaged list for sorting sorted_conference_rankings = [] for conference in conference_rankings: sorted_conference_rankings.append({ "conference": conference, "score": statistics.mean(conference_rankings[conference]) }) # Sort conference rankings by average team score sorted_conference_rankings = sorted(sorted_conference_rankings, key=lambda p: p["score"], reverse=True) # Print conference rankings rank = 1 conference_rankings_file_string = "Conference,Score\n" for conference_ranking in sorted_conference_rankings: # Print to file string in csv format conference = conference_ranking["conference"] score = conference_ranking["score"] conference_rankings_file_string += f"{conference},{score:.1f}\n" # Print to console in pretty format print(f"{rank}: {conference}, Score: {score:.1f}") rank += 1 # Create the conference rankings file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/rankings/{year}/conference_rankings-{year}-{week:02}.csv" utils.write_string(conference_rankings_file_string, filename)
def calculate_model(year, week, stats, teams): if week < 9: prev_stats = the_kick_is_bad.read_stats(year - 1, "bowl") prev_model = read_model(year - 1, "bowl") else: prev_stats = None prev_model = None games_played = calculate_games_played(week, stats, teams) points_margin = calculate_points_margin(week, stats, prev_stats, games_played, teams) rushing_yards_margin = calculate_rushing_yards_margin( week, stats, prev_stats, games_played, teams) home_field_corrections = calculate_home_field_corrections( week, stats, prev_stats, prev_model, games_played, teams) games_played_normalization = calculate_games_played_normalization( week, stats, games_played, teams) strengths = calculate_strengths(week, points_margin, rushing_yards_margin, home_field_corrections, games_played, games_played_normalization, prev_model, teams) average_opponent_strengths = np.matmul(games_played_normalization, strengths) standard_deviations = calculate_standard_deviations( year, week, prev_model, teams) model = {} i = 0 for team in teams: model[team] = { "strength": strengths[i], "standard deviation": standard_deviations[i], "points margin": points_margin[i], "average opponent strength": average_opponent_strengths[i], "rushing yards margin": rushing_yards_margin[i], "home field correction": home_field_corrections[i], "games played": games_played[i] } i += 1 # Print predictions model_file_string = "Team,Strength,StandardDeviation,PointsMargin,AverageOpponentStrength,RushingYardsMargin,HomeFieldCorrection,GamesPlayed\n" for team in model: # Print to file string in csv format model_file_string += "{0},{1},{2},{3},{4},{5},{6},{7:.0f}\n".format( team, model[team]["strength"], model[team]["standard deviation"], model[team]["points margin"], model[team]["average opponent strength"], model[team]["rushing yards margin"], model[team]["home field correction"], model[team]["games played"]) # Create the predictions file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/{year}/model-{year}-{week:02}.csv" utils.write_string(model_file_string, filename) return model, strengths, standard_deviations
def evaluate(year, week): predictions = read_predictions(year, week) scores = the_kick_is_bad.read_scores(year, week) # Loop through predictions to check results results = [] for prediction in predictions: away_team = prediction["away team"] home_team = prediction["home team"] predicted_winner = prediction["predicted winner"] predicted_margin_of_victory = prediction["predicted margin of victory"] # Loop through all scores to find the matching (completed) game for game in scores["games"]: if game["game"]["gameState"] != "final": continue # Check if this is the same game by comparing team names if game["game"]["away"]["names"]["standard"] == away_team and game["game"]["home"]["names"]["standard"] == home_team: away_score = int(game["game"]["away"]["score"]) home_score = int(game["game"]["home"]["score"]) # Get the actual results if away_score > home_score: actual_winner = away_team elif home_score > away_score: actual_winner = home_team else: actual_winner = "TIE" actual_margin_of_victory = abs(away_score - home_score) # Save the results data results.append({ "away team": away_team, "home team": home_team, "predicted winner": predicted_winner, "actual winner": actual_winner, "predicted margin of victory": predicted_margin_of_victory, "actual margin of victory": actual_margin_of_victory }) break # Print results num_results = len(results) num_correct = 0 results_file_string = "AwayTeam,HomeTeam,PredictedWinner,Result,PredictedMoV,ActualMoV\n" for result in results: # Determine if prediction was correct if result["predicted winner"] == result["actual winner"]: result_string = "RIGHT" num_correct += 1 else: result_string = "WRONG" result["actual margin of victory"] *= -1 # Print to file string in csv format results_file_string += "{0},{1},{2},{3},{4:.1f},{5}\n".format(result["away team"], result["home team"], result["predicted winner"], result_string, result["predicted margin of victory"], result["actual margin of victory"]) # Print to console strin in pretty format if result["predicted winner"] == result["home team"]: predicted_loser = result["away team"] else: predicted_loser = result["home team"] results_console_string = "{0}: Predicted {1} over {2} by {3:.1f} (actual: {4})".format(result_string, result["predicted winner"], predicted_loser, result["predicted margin of victory"], result["actual margin of victory"]) print(results_console_string) # Print statistics to console accuracy = num_correct / num_results * 100 print(f"({num_correct}/{num_results}) {accuracy:.1f}%") # Create the results file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/predictions/{year}/results-{year}-{week:02}.csv" utils.write_string(results_file_string, filename)
def evaluate_model(): results = {} start_year = 2013 end_year = 2020 max_num_weeks = 16 all_num_games = 0 all_num_correct = 0 conf_num_games = 0 conf_num_correct = 0 nonconf_num_games = 0 nonconf_num_correct = 0 champ_num_games = 0 champ_num_correct = 0 fcs_num_games = 0 fcs_num_correct = 0 bowl_num_games = 0 bowl_num_correct = 0 yearly_num_games = [] for _ in range(0, end_year - start_year + 1): yearly_num_games.append(0) yearly_num_correct = [] for _ in range(0, end_year - start_year + 1): yearly_num_correct.append(0) weekly_num_games = [] for _ in range(0, max_num_weeks): weekly_num_games.append(0) weekly_num_correct = [] for _ in range(0, max_num_weeks): weekly_num_correct.append(0) for year in range(start_year, end_year + 1): year_idx = year - start_year teams, _ = the_kick_is_bad.read_teams(year) num_weeks = the_kick_is_bad.read_number_of_weeks(year) for week in range(1, num_weeks + 1): week_idx = week - 1 print( f"Processing evaluation data from year {year}, week {week:02}..." ) rankings = read_rankings(year, week - 1) scores = the_kick_is_bad.read_scores(year, week) # Loop through scores to make predictions for game in scores["games"]: # Get the team names away_team = game["game"]["away"]["names"]["standard"] home_team = game["game"]["home"]["names"]["standard"] # Check if this is a valid game if game["game"]["gameState"] != "final": continue # Get the actual results away_score = int(game["game"]["away"]["score"]) home_score = int(game["game"]["home"]["score"]) if away_score > home_score: home_won = 0 elif away_score < home_score: home_won = 1 else: continue # Determine home field advantage # Assume all bowl games are neutral site home_field_advantage = 4 # Get away team strength away_team_strength = rankings[away_team]["strength"] # Get home team strength and add home field advantage home_team_strength = rankings[home_team][ "strength"] + home_field_advantage # Pick the winner based on team strength if home_team_strength >= away_team_strength: prediction = 1 else: prediction = 0 # Determine if the result was right if home_won == prediction: is_correct = 1 else: is_correct = 0 # Increment relevant result counters all_num_games += 1 all_num_correct += is_correct # Conference/non-conference away_team_conference = teams[away_team]["conference"] home_team_conference = teams[home_team]["conference"] if away_team_conference == home_team_conference: conf_num_games += 1 conf_num_correct += is_correct elif away_team != "FCS" and home_team != "FCS": nonconf_num_games += 1 nonconf_num_correct += is_correct # Championship if (week == num_weeks - 1) and (away_team_conference == home_team_conference): champ_num_games += 1 champ_num_correct += is_correct # FCS if away_team == "FCS" or home_team == "FCS": fcs_num_games += 1 fcs_num_correct += is_correct # Yearly yearly_num_games[year_idx] += 1 yearly_num_correct[year_idx] += is_correct # Weekly weekly_num_games[week_idx] += 1 weekly_num_correct[week_idx] += is_correct # Add bowl week week_idx = num_weeks print(f"Processing evaluation data from year {year}, week 'bowl'...") scores = the_kick_is_bad.read_scores(year, "bowl") for game in scores["games"]: # Get the team names away_team = game["game"]["away"]["names"]["standard"] home_team = game["game"]["home"]["names"]["standard"] # Check if this is a valid game if game["game"]["gameState"] != "final": continue # Get the actual results away_score = int(game["game"]["away"]["score"]) home_score = int(game["game"]["home"]["score"]) if away_score > home_score: home_won = 0 elif away_score < home_score: home_won = 1 else: continue # Determine home field advantage # Assume all bowl games are neutral site home_field_advantage = 0 # Get away team strength away_team_strength = rankings[away_team]["strength"] # Get home team strength and add home field advantage home_team_strength = rankings[home_team][ "strength"] + home_field_advantage # Pick the winner based on team strength if home_team_strength >= away_team_strength: prediction = 1 else: prediction = 0 # Determine if the result was right if home_won == prediction: is_correct = 1 else: is_correct = 0 # Increment relevant result counters all_num_games += 1 all_num_correct += is_correct # Bowl bowl_num_games += 1 bowl_num_correct += is_correct # Yearly yearly_num_games[year_idx] += 1 yearly_num_correct[year_idx] += is_correct # Calculate final results results["all"] = (all_num_correct / all_num_games) * 100 results["conference"] = (conf_num_correct / conf_num_games) * 100 results["non_conference"] = (nonconf_num_correct / nonconf_num_games) * 100 results["championship"] = (champ_num_correct / champ_num_games) * 100 results["fcs"] = (fcs_num_correct / fcs_num_games) * 100 results["bowl"] = (bowl_num_correct / bowl_num_games) * 100 for year_idx in range(0, end_year - start_year + 1): results[f"year {start_year + year_idx}"] = ( yearly_num_correct[year_idx] / yearly_num_games[year_idx]) * 100 for week_idx in range(0, max_num_weeks): results[f"week {1 + week_idx}"] = (weekly_num_correct[week_idx] / weekly_num_games[week_idx]) * 100 # Save the evaluation results to file absolute_path = utils.get_abs_path(__file__) results_filename = f"{absolute_path}/model_evalation.json" utils.write_json(results, results_filename)
def predict(year, week): scores = the_kick_is_bad.read_scores(year, week) rankings = read_rankings(year, week - 1) # Check if the week is 'bowl' week num_weeks = the_kick_is_bad.read_number_of_weeks(year) week, _ = utils.check_week(week, num_weeks) # Loop through scores to make predictions predictions = [] for game in scores["games"]: # Get the team names away_team = game["game"]["away"]["names"]["standard"] home_team = game["game"]["home"]["names"]["standard"] # Determine home field advantage # Assume all bowl games are neutral site if week <= num_weeks: home_field_advantage = 4 else: home_field_advantage = 0 # Get away team strength away_team_strength = rankings[away_team]["strength"] # Get home team strength and add home field advantage home_team_strength = rankings[home_team][ "strength"] + home_field_advantage # Pick the winner based on team strength if home_team_strength >= away_team_strength: predicted_winner = home_team predicted_margin_of_victory = home_team_strength - away_team_strength else: predicted_winner = away_team predicted_margin_of_victory = away_team_strength - home_team_strength # Calculate the game interest score game_interest = rankings[away_team]["team score"] + rankings[ home_team]["team score"] - predicted_margin_of_victory # Pack predictions predictions.append({ "away team": away_team, "home team": home_team, "predicted winner": predicted_winner, "predicted margin of victory": predicted_margin_of_victory, "game interest": game_interest }) # Sort predictions by game interest predictions = sorted(predictions, key=lambda p: p["game interest"], reverse=True) # Print predictions predictions_file_string = "AwayTeam,HomeTeam,PredictedWinner,PredictedMoV,GameInterest\n" for prediction in predictions: # Print to console in pretty format print( "{0} @ {1}: Predicted Winner: {2}, Predicted MoV: {3:.1f}, Game Interest: {4:.1f}" .format(prediction["away team"], prediction["home team"], prediction["predicted winner"], prediction["predicted margin of victory"], prediction["game interest"])) # Print to file string in csv format predictions_file_string += "{0},{1},{2},{3:.1f},{4:.1f}\n".format( prediction["away team"], prediction["home team"], prediction["predicted winner"], prediction["predicted margin of victory"], prediction["game interest"]) # Create the predictions file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/predictions/{year}/predictions-{year}-{week:02}.csv" utils.write_string(predictions_file_string, filename)
def calculate_team_rankings(year, week, stats, teams): _, strengths, standard_deviations = calculate_model(year, week, stats, teams) # strengths = get_model_array(model, "strength") normalized_strengths = strengths - min(strengths) # standard_deviations = get_model_array(model, "standard deviation") if week > 0: prev_rankings = read_rankings(year, week - 1) if week == 0: team_scores = normalized_strengths * 0.5 else: wins = get_wins_array(stats, teams) games_played = get_games_played_array(stats, teams) team_scores = normalized_strengths * (wins + 2) / (games_played + 4) sort_indexes = np.argsort(-team_scores) rankings = {} i = 0 if week > 0: for team in teams: rankings[team] = { "rank": np.where(sort_indexes == i)[0][0] + 1, "previous rank": prev_rankings[team]["rank"], "delta rank": prev_rankings[team]["rank"] - (np.where(sort_indexes == i)[0][0] + 1), "team score": team_scores[i], "strength": strengths[i], "standard deviation": standard_deviations[i] } i += 1 else: for team in teams: rankings[team] = { "rank": np.where(sort_indexes == i)[0][0] + 1, "previous rank": 0, "delta rank": 0 - (np.where(sort_indexes == i)[0][0] + 1), "team score": team_scores[i], "strength": strengths[i], "standard deviation": standard_deviations[i] } i += 1 # Print teamrankings team_rankings_file_string = "Team,Rank,PrevRank,DeltaRank,TeamScore,Strength,StandardDeviation\n" for team in rankings: # Print to file string in csv format team_rankings_file_string += "{0},{1:.0f},{2:.0f},{3:.0f},{4:.1f},{5:.1f},{6:.1f}\n".format(team, rankings[team]["rank"], rankings[team]["previous rank"], rankings[team]["delta rank"], rankings[team]["team score"], rankings[team]["strength"], rankings[team]["standard deviation"]) teams_list = [] for team in teams: teams_list.append(team) for index in sort_indexes: team = teams_list[index] team_rankings_string = "{0:.0f} ({1:.0f}): {2}, Team Score: {3:.1f}, Strength: {4:.1f}, Std: {5:.1f}".format(rankings[team]["rank"], rankings[team]["delta rank"], team, rankings[team]["team score"], rankings[team]["strength"], rankings[team]["standard deviation"]) print(team_rankings_string) # Create the predictions file with absolute path absolute_path = utils.get_abs_path(__file__) filename = f"{absolute_path}/rankings/{year}/team_rankings-{year}-{week:02}.csv" utils.write_string(team_rankings_file_string, filename) return rankings