| """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 |
| """ |
| |
| 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() |
| |
| |
| 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 |
| } |
|
|
|
|
| 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 = [] |
| |
| |
| games_df = games_df.sort_values('date').reset_index(drop=True) |
| |
| |
| 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_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' |
| } |
|
|
| |
| TEAM_ABBREVS = {v: k for k, v in NBA_TEAMS.items()} |
|
|