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

Description of Text

Description of Text

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>