My project
I create a feature that will allow a user to imput two NBA teams and get a predicted winner between the two. It also displays the winrates of the teams. See below
The code
-
This is the CSV data set I am using that contains alot of game date from the NBA since 2000. It stores the team names in numerical ID, so I had some extra work mapping the plain text team names to their IDs.
-
This is my Model code that uses the data for the CSV file, and does the calculations using the team names and scores. The data is cleaned, and used in linear regretion and decision tree machine learning.
import pandas as pd
sklearn.tree import DecisionTreeRegressor
from sklearn.linear_model import LinearRegression
class BasketBallScoreModel:
_instance = None
def __init__(self):
self.model = None
self.dt = None
self.features = ['PTS_away', 'FG_PCT_away', 'FT_PCT_away', 'FG3_PCT_away', 'AST_away', 'REB_away',
'PTS_home', 'FG_PCT_home', 'FT_PCT_home', 'FG3_PCT_home', 'AST_home', 'REB_home']
self.target = 'HOME_TEAM_WINS'
self.basketball_data = None
def _clean(self):
# Drop rows with missing values in relevant columns
self.basketball_data.dropna(subset=self.features + [self.target], inplace=True)
# Convert categorical columns to appropriate data types
self.basketball_data['HOME_TEAM_ID'] = self.basketball_data['HOME_TEAM_ID'].astype(int)
self.basketball_data['VISITOR_TEAM_ID'] = self.basketball_data['VISITOR_TEAM_ID'].astype(int)
def _train(self):
X = self.basketball_data[self.features]
y = self.basketball_data[self.target]
self.model = LinearRegression()
self.model.fit(X, y)
self.dt = DecisionTreeRegressor()
self.dt.fit(X, y)
@classmethod
def get_instance(cls):
if cls._instance is None:
cls._instance = cls()
cls._instance._load_data()
cls._instance._clean()
cls._instance._train()
return cls._instance
def _load_data(self):
self.basketball_data = pd.read_csv('nba_data.csv')
def predict_winner_likelihood(self, team1_id, team2_id):
# Filter past data for matches involving the two teams
team1_matches = self.basketball_data[(self.basketball_data['HOME_TEAM_ID'] == team1_id) | (self.basketball_data['VISITOR_TEAM_ID'] == team1_id)]
team2_matches = self.basketball_data[(self.basketball_data['HOME_TEAM_ID'] == team2_id) | (self.basketball_data['VISITOR_TEAM_ID'] == team2_id)]
# Concatenate the filtered data to get all matches involving both teams
matches = pd.concat([team1_matches, team2_matches])
# Check if matches DataFrame is empty
if matches.empty:
return {"error": "No past matches found for the given teams."}
# Calculate the average points scored by each team in past matches
team1_avg_score = (matches[matches['HOME_TEAM_ID'] == team1_id]['PTS_home'].mean() or 0) + (matches[matches['VISITOR_TEAM_ID'] == team1_id]['PTS_away'].mean() or 0)
team2_avg_score = (matches[matches['HOME_TEAM_ID'] == team2_id]['PTS_home'].mean() or 0) + (matches[matches['VISITOR_TEAM_ID'] == team2_id]['PTS_away'].mean() or 0)
# Calculate the total points scored in past matches involving both teams
total_score = team1_avg_score + team2_avg_score
# Calculate the percentage likelihood for each team to win
team1_likelihood = (team1_avg_score / total_score) * 100
team2_likelihood = (team2_avg_score / total_score) * 100
return {team1_id: team1_likelihood, team2_id: team2_likelihood}
def feature_weights(self):
return {feature: importance for feature, importance in zip(self.features, self.dt.feature_importances_)}
- This is my API endpoint code, that creates the api so my frontend can fetch the data from the backend. It imputs the two teams ID into the predict winner function, which is from my model, and returns the output.
from flask import Blueprint, request, jsonify
from flask_restful import Api, Resource
from model.NBAmodel import BasketBallScoreModel # Import the NBA model class
NBA_api = Blueprint('NBA_api', __name__, url_prefix='/api/NBA')
api = Api(NBA_api)
class Predict(Resource):
def post(self):
# Get the team data from the request
data = request.get_json()
# Get the team IDs from the data
team1_id = data.get('team1_id')
team2_id = data.get('team2_id')
basketball_model = BasketBallScoreModel.get_instance()
# Predict the winner likelihood of the NBA game
likelihood = basketball_model.predict_winner_likelihood(team1_id, team2_id)
return jsonify(likelihood)
# Add the Predict resource to the API with the /predict endpoint
api.add_resource(Predict, '/predict')
- The frontend is just an HTML form with two imput boxes with dropdown menus containing all of the team in the NBA. There is a javascript function that maps the imputed team name, to the teams id that is used in the backend. The code fetches the data from the backend API, and then displays it along with an image of the winning team logo.
<body style="background-image: url('plac'); background-size: cover;">
<form id="nbaForm">
<label for="team1">Home Team:</label>
<select id="team1" name="team1" required>
<option value="">Select Home Team</option>
</select><br><br>
<label for="team2">Away Team:</label>
<select id="team2" name="team2" required>
<option value="">Select Away Team</option>
</select><br><br>
<button type="button" onclick="predictWinner()">Predict Winner</button>
</form>
<div id="result">
<h2>Predicted Winner</h2>
<p id="winningTeam"></p>
<img id="winningTeamLogo" src="" alt="Winning Team Logo">
</div>
<script>
var teamNameToID = {
"Atlanta Hawks": 1610612737,
"Boston Celtics": 1610612738,
"Brooklyn Nets": 1610612751,
"Charlotte Hornets": 1610612766,
"Chicago Bulls": 1610612741,
"Cleveland Cavaliers": 1610612739,
"Dallas Mavericks": 1610612742,
"Denver Nuggets": 1610612743,
"Detroit Pistons": 1610612765,
"Golden State Warriors": 1610612744,
"Houston Rockets": 1610612745,
"Indiana Pacers": 1610612754,
"LA Clippers": 1610612746,
"Los Angeles Lakers": 1610612747,
"Memphis Grizzlies": 1610612763,
"Miami Heat": 1610612748,
"Milwaukee Bucks": 1610612749,
"Minnesota Timberwolves": 1610612750,
"New Orleans Pelicans": 1610612740,
"New York Knicks": 1610612752,
"Oklahoma City Thunder": 1610612760,
"Orlando Magic": 1610612753,
"Philadelphia 76ers": 1610612755,
"Phoenix Suns": 1610612756,
"Portland Trail Blazers": 1610612757,
"Sacramento Kings": 1610612758,
"San Antonio Spurs": 1610612759,
"Toronto Raptors": 1610612761,
"Utah Jazz": 1610612762,
"Washington Wizards": 1610612764
};
function populateDropdowns() {
var team1Select = document.getElementById("team1");
var team2Select = document.getElementById("team2");
for (var teamName in teamNameToID) {
var option1 = document.createElement("option");
var option2 = document.createElement("option");
option1.value = teamName;
option1.textContent = teamName;
team1Select.appendChild(option1);
option2.value = teamName;
option2.textContent = teamName;
team2Select.appendChild(option2);
}
}
populateDropdowns();
function predictWinner() {
var form = document.getElementById('nbaForm');
var team1 = document.getElementById('team1').value;
var team2 = document.getElementById('team2').value;
var resultDiv = document.getElementById('result');
var winningTeamElement = document.getElementById('winningTeam');
var winningTeamLogoElement = document.getElementById('winningTeamLogo');
var team1ID = teamNameToID[team1];
var team2ID = teamNameToID[team2];
var data = {
"team1_id": team1ID,
"team2_id": team2ID
};
fetch('http://localhost:8086/api/NBA/predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify(data)
})
.then(response => response.json())
.then(data => {
var winningTeamID = Object.keys(data).reduce((a, b) => data[a] > data[b] ? a : b);
var winningTeamName = Object.keys(teamNameToID).find(key => teamNameToID[key] === parseInt(winningTeamID));
winningTeamElement.textContent = winningTeamName + ' wins with ' + data[winningTeamID].toFixed(4) + '% win rate!';
winningTeamLogoElement.src = 'images/' + winningTeamName + '.png';
for (var teamID in data) {
var winRate = data[teamID].toFixed(4);
var teamName = Object.keys(teamNameToID).find(key => teamNameToID[key] === parseInt(teamID));
resultDiv.innerHTML += '<p>' + teamName + ': ' + winRate + '%</p>';
}
})
.catch(error => {
console.error('Error:', error);
});
}
</script>
</body>