Welcome to bracketology’s documentation!¶
The goal of bracketology is to speed up the analysis of NCAA march madness data and help develop algorithms for filling out brackets.
Before You Start¶
- Here are the main things you need to know:
- The main parts of this package are the
Bracket
objects and simulator functions in thesimulators
module - A Bracket is composed of
Team
andGame
objects - Game objects have two Team objects as attributes, and the round number
- Teams have a name, seed, and dictionary for statistics
- Simulator functions have 1 argument of type Game, and return the winning Team of that Game
- The main parts of this package are the
Getting Started¶
Import bracketology and create a bracket from last year.
from bracketology import Bracket, Game, Team
# Create a bracket object from 2019
year = 2019
b19 = Bracket(year)
Tutorial¶
Inspecting the Bracket Object¶
Here are three different ways you can inspect the Bracket.
- Inspect teams in each region (dictionary of actual results)
- Inspect actual results by round (dictionary)
- Inspect simulated results by round (list of Team attributes)
Get Teams in each Region¶
Print out all the teams in each region. The regions attribute is a dictionary with the information of all the teams in each region.
>>> print(b19.regions)
{
'East': [{'Team': 'Duke', 'Seed': 1},
{'Team': 'Michigan St', 'Seed': 2},
{'Team': 'LSU', 'Seed': 3},
...],
'West': [{'Team': 'Gonzaga', 'Seed': 1},
{'Team': 'Michigan', 'Seed': 2},
{'Team': 'Texas Tech', 'Seed': 3},
...],
'Midwest': [{'Team': 'North Carolina', 'Seed': 1},
{'Team': 'Kentucky', 'Seed': 2},
{'Team': 'Houston', 'Seed': 3},
...],
'South': [{'Team': 'Virginia', 'Seed': 1},
{'Team': 'Tennessee', 'Seed': 2},
{'Team': 'Purdue', 'Seed': 3},
...]
}
Actual Results by Round¶
The result attribute will return a dictionary (similar to regions above) but will be broken out by which teams actually made it to each round. You can use it to inspect the real tournament results.
>>> print(b19.result.keys())
dict_keys(['first', 'second', 'sweet16', 'elite8', 'final4', 'championship', 'winner'])
>>> print(b19.result['final4'])
[{'Team': 'Michigan St', 'Seed': 2}, {'Team': 'Virginia', 'Seed': 1},
{'Team': 'Texas Tech', 'Seed': 3}, {'Team': 'Auburn', 'Seed': 5}]
>>> print(b19.result.get('winner'))
{'Team': 'Virginia', 'Seed': 1}
Simulation Results by Round¶
Print out all the teams that are simulated to make it to each round. The first round is filled out by default. This is a list of Team objects that are simulated to make it to each round. Right now round2 is an empty list because we have not simulated the bracket yet.
>>> print(b19.round1)
[<1 Duke>, <2 Michigan St>, <3 LSU>, ... , <1 Gonzaga>, <2 Michigan>, <3 Texas Tech>,
... , <1 North Carolina>, <2 Kentucky>, <3 Houston>, ... , <1 Virginia>, <2 Tennessee>, <3 Purdue>]
>>> print(b19.round2)
[]
Creating a Simulator Algorithm¶
A simulator function needs to take in a Game and Return a Team.
First we create some faux teams and games to test our simulator function on.
# Create teams
team1 = Team(name='Blue Mountain State',seed=1)
team2 = Team(name='School of Hard Knocks',seed=2)
# Create a game between the teams
game1 = Game(team1, team2, round_number=1)
Then we define the simulator function.
import random
def pick_a_random_team(the_game):
# Extract Teams from Game
team1 = the_game.top_team
team2 = the_game.bottom_team
# Randomly select a winner
if random.random() < 0.5:
winner = team1
else:
winner = team2
# Return the lucky team
return winner
Test the function out on a game.
>>> pick_a_random_team(game1)
<2 School of Hard Knocks>
Let’s run some simulations with our function!
# Initialize Simulation Parameters
BMS_wins = 0
HardKnocks_wins = 0
n_games = 1000
# Loop through a bunch of games
for i in range(n_games):
# Simulate the winner
winner = pick_a_random_team(game1)
# Increment win totals
if winner.seed == 1:
BMS_wins += 1
elif winner.seed == 2:
HardKnocks_wins += 1
else:
raise Exception("We have a tie??")
# Calculate total win percentage
BMS_win_pct = round(BMS_wins/n_games, 4) * 100
HardKnocks_win_pct = round(HardKnocks_wins/n_games, 4) * 100
# Print out results
print(f"Blue Mountain State Win Percentage: %{BMS_win_pct}")
print(f"School of Hard Knocks Win Percentage: %{HardKnocks_win_pct}")
Output:
Blue Mountain State Win Percentage: %50.9
School of Hard Knocks Win Percentage: %49.1
Evaluting Simulator Results¶
Let’s evaluate our simulator function on some actual brackets.
# Initialize simulation parameters
n_sims = 1000 # number of times to simulate through all years
total_sims = (n_sims * len(brackets))
scores = []
correct_games = []
# Loop through a plethora of brackets
for i in range(n_sims):
for bracket in brackets:
# Run the algorithm on the bracket
bracket.score(sim_func=pick_a_random_team, verbose=False)
# Save the scoring results in a list
scores.append(bracket.total_score)
correct_games.append(bracket.n_games_correct)
# Calculate the average across all simulations
avg_score = round(sum(scores) / total_sims)
avg_correct = round(sum(correct_games) / total_sims)
# Print result
print(f"Average number total score {avg_score}/192")
print(f"Average number of games guessed correctly {avg_correct}/64")
Output:
Average number total score 31/192
Average number of games guessed correctly 21/64
Easy, right!
Reference¶
Bracket Objects¶
-
class
bracketology.
Bracket
(year)¶ A NCAA tournament for a specific year
-
year
¶ Calendar year of the tournament (1985-2019)
Type: int
-
result
¶ The actual tournament results for that year
Type: (dict)
-
regions
¶ The teams that year broken down by region
Type: (dict)
-
East
¶ SubBracket for East
Type: (SubBracket16)
-
West
¶ SubBracket for West
Type: (SubBracket16)
-
Midwest
¶ SubBracket for Midwest
Type: (SubBracket16)
-
South
¶ SubBracket for South
Type: (SubBracket16)
-
round1, round2, ... , round6
Which teams are simulated to make it to each round
Type: (list of Teams)
-
n_games_correct int
Number of games the simulation got correct
-
total_score int
Total points earned by the simulator function (32 points per round)
-
__init__
(year)¶ Parameters: year (int) – Year of the NCAA tournament
-
score
(sim_func=None, verbose=True)¶ Calculates the number of games correct from the simulation and that total score (32 points per round). Will run a new simulation as well if passed sim_func argument.
Parameters: - sim_func (function, optional) – A function that take in Game and returns a Team of that Game. Can be null if the bracket has already been simulated
- verbose (bool, optional) – Whether or not to print the score. If False, will not print score, only sets the n_games_correct and total_score parameters. The default is True.
-
sim
(sim_func)¶ Simulate the entire bracket with sim_func, from first round to deciding the winner
Parameters: sim_func (function) – A function that take in Game and returns a Team of that Game
-
-
class
bracketology.
SubBracket16
(region)¶ A region, or sub-bracket of 16 teams for a NCAA tournament
-
region
¶ Name of the region for the bracket
Type: str
-
team01, ..., team16
Each team in the subracket named for its seed
Type: Team
-
Game1, ..., Game15
The games that make up the bracket. Round 1 is 1-8, Round 2 is 9-12, Sweet 16 is 13 and 14, Final Four is 15
Type: Game
-
round1, ..., round6
List of games in each round
Type: list
-
__init__
(region)¶ Parameters: region (str) – Name of the region for this sub bracket.
-
initialize_first_round
(teams)¶
-
run_bracket
(sim_func)¶
-
-
class
bracketology.
FinalFour
(year)¶ A bracket of four teams to simulate the final four of a NCAA tournamnet
-
__init__
(year)¶ Parameters: year (int) – Year of the NCAA tournament
-
set_matches
(teams)¶
-
-
class
bracketology.
Game
(top_team, bottom_team, round_number)¶ A game between two teams in the bracket
-
round_number
¶ Which round of the tournament is it (1-6)
Type: int
-
__init__
(top_team, bottom_team, round_number)¶ Parameters:
-
-
class
bracketology.
Team
(name, seed)¶ A team that is in a Game or a Bracket
-
name
¶ Name of the school (or abbreviation)
Type: str
-
seed
¶ Seed of the team in the tournament (1-16)
Type: int
-
stats
¶ A dictionary with other information about the team, like season stats
Type: (dict)
-
__init__
(name, seed)¶ Parameters: - name (str) – The name of the school for the team.
- seed (int) – The seed of the team in the bracket.
-
Simulators¶
-
bracketology.
simulators
¶ alias of
bracketology.simulators
-
class
bracketology.simulators.
upset_prob
¶ Given a probability between 0-1 will return a function that can be as an algorithm to fill out an NCAA bracket with p as the probability of an upset
Parameters: p (float) – The probability of an upset Returns: scoring_func – function to pick an upset of a Game with probability p Return type: function