ianalloway's picture
Initial model upload: XGBoost NBA game predictor + model card + training scripts
602995c verified
Raw
History Blame Contribute Delete
5.03 kB
"""Feature engineering for NBA game prediction."""
import pandas as pd
import numpy as np
from typing import Tuple
def calculate_team_stats(games_df: pd.DataFrame, team: str, n_games: int = 10) -> dict:
"""
Calculate rolling statistics for a team based on recent games.
Args:
games_df: DataFrame with game results
team: Team name
n_games: Number of recent games to consider
Returns:
Dictionary of team statistics
"""
# Filter games where team played
team_games = games_df[
(games_df['home_team'] == team) | (games_df['away_team'] == team)
].tail(n_games)
if len(team_games) == 0:
return get_default_stats()
# Calculate wins
wins = 0
points_for = []
points_against = []
for _, game in team_games.iterrows():
if game['home_team'] == team:
points_for.append(game['home_score'])
points_against.append(game['away_score'])
if game['home_score'] > game['away_score']:
wins += 1
else:
points_for.append(game['away_score'])
points_against.append(game['home_score'])
if game['away_score'] > game['home_score']:
wins += 1
return {
'win_pct': wins / len(team_games),
'avg_points_for': np.mean(points_for),
'avg_points_against': np.mean(points_against),
'point_diff': np.mean(points_for) - np.mean(points_against),
'games_played': len(team_games)
}
def get_default_stats() -> dict:
"""Return default stats for teams with no data."""
return {
'win_pct': 0.5,
'avg_points_for': 110,
'avg_points_against': 110,
'point_diff': 0,
'games_played': 0
}
def create_game_features(
home_team: str,
away_team: str,
home_stats: dict,
away_stats: dict
) -> dict:
"""
Create features for a single game prediction.
Args:
home_team: Home team name
away_team: Away team name
home_stats: Home team statistics
away_stats: Away team statistics
Returns:
Dictionary of features for the game
"""
return {
'home_win_pct': home_stats['win_pct'],
'away_win_pct': away_stats['win_pct'],
'home_ppg': home_stats['avg_points_for'],
'away_ppg': away_stats['avg_points_for'],
'home_opp_ppg': home_stats['avg_points_against'],
'away_opp_ppg': away_stats['avg_points_against'],
'home_point_diff': home_stats['point_diff'],
'away_point_diff': away_stats['point_diff'],
'win_pct_diff': home_stats['win_pct'] - away_stats['win_pct'],
'point_diff_diff': home_stats['point_diff'] - away_stats['point_diff'],
'home_advantage': 1 # Home court advantage indicator
}
def prepare_training_data(games_df: pd.DataFrame) -> Tuple[pd.DataFrame, pd.Series]:
"""
Prepare training data from historical games.
Args:
games_df: DataFrame with historical game results
Returns:
Tuple of (features DataFrame, target Series)
"""
features_list = []
targets = []
# Sort by date
games_df = games_df.sort_values('date').reset_index(drop=True)
# Need at least 20 games before we can make predictions
for i in range(20, len(games_df)):
game = games_df.iloc[i]
historical = games_df.iloc[:i]
home_stats = calculate_team_stats(historical, game['home_team'])
away_stats = calculate_team_stats(historical, game['away_team'])
features = create_game_features(
game['home_team'],
game['away_team'],
home_stats,
away_stats
)
features_list.append(features)
targets.append(1 if game['home_score'] > game['away_score'] else 0)
return pd.DataFrame(features_list), pd.Series(targets)
# NBA team name mappings for consistency
NBA_TEAMS = {
'ATL': 'Atlanta Hawks',
'BOS': 'Boston Celtics',
'BKN': 'Brooklyn Nets',
'CHA': 'Charlotte Hornets',
'CHI': 'Chicago Bulls',
'CLE': 'Cleveland Cavaliers',
'DAL': 'Dallas Mavericks',
'DEN': 'Denver Nuggets',
'DET': 'Detroit Pistons',
'GSW': 'Golden State Warriors',
'HOU': 'Houston Rockets',
'IND': 'Indiana Pacers',
'LAC': 'Los Angeles Clippers',
'LAL': 'Los Angeles Lakers',
'MEM': 'Memphis Grizzlies',
'MIA': 'Miami Heat',
'MIL': 'Milwaukee Bucks',
'MIN': 'Minnesota Timberwolves',
'NOP': 'New Orleans Pelicans',
'NYK': 'New York Knicks',
'OKC': 'Oklahoma City Thunder',
'ORL': 'Orlando Magic',
'PHI': 'Philadelphia 76ers',
'PHX': 'Phoenix Suns',
'POR': 'Portland Trail Blazers',
'SAC': 'Sacramento Kings',
'SAS': 'San Antonio Spurs',
'TOR': 'Toronto Raptors',
'UTA': 'Utah Jazz',
'WAS': 'Washington Wizards'
}
# Reverse mapping
TEAM_ABBREVS = {v: k for k, v in NBA_TEAMS.items()}