Skip to content

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

NBA Playoffs Predictor

Python FastAPI Scikit-learn Supabase React Vite Tailwind CSS

NBA Playoff AI Match Analysis System

An end-to-end full-stack ML application that compares NBA teams using advanced stats, simulates matchup outcomes, and supports real-time "What-If" scenario testing through interactive sliders.

Project Preview

NBA Playoff AI Dashboard

This project includes:

  • A Python data pipeline to pull NBA data and store it in Supabase
  • A trained Random Forest model for team strength/championship probability
  • A FastAPI backend for team data + prediction endpoints
  • A React + Vite frontend dashboard for matchup selection, sliders, and visualization

What This Project Does

  • Pulls multi-season NBA team advanced metrics (offense, defense, net, pace, efficiency)
  • Trains a model on historical seasons to estimate team-level championship probability
  • Converts two team probabilities into head-to-head matchup percentages
  • Lets you tweak team inputs with sliders (offense/defense/pace) and re-runs predictions instantly
  • Shows transparent stat comparison tables so predictions are explainable

How I Built It

I built this project in phases:

  1. Data first
    Started with nba_api to fetch regular-season advanced team stats and standings labels.

  2. Storage + repeatability
    Pushed season rows into Supabase with upserts (team_id,season) so I could re-run ingestion safely.

  3. Model training
    Trained a RandomForestClassifier on historical team-season features with championship labels.

  4. API layer
    Wrapped model + data lookup with FastAPI endpoints (/api/teams, /api/team/{team_id}/stats, /api/predict).

  5. UI + interaction
    Built a dense dashboard in React with team selection, prediction bar, stat table, and adjustment sliders.

  6. Calibration fixes
    Added season-awareness (2025-26 support/fallback) and softened extreme 0/100 outputs in matchup conversion.


Model Overview

Target

The model is trained to predict:

  • won_championship (binary classification at team-season level)

Feature Set

The model uses these features:

  • off_rating
  • def_rating
  • net_rating
  • pace
  • ts_pct
  • w_pct

Training Script

Training logic lives in:

  • data_pipeline/scripts/train_model.py

Key training details:

  • Model: RandomForestClassifier
  • n_estimators=300
  • max_depth=6
  • min_samples_leaf=2
  • class_weight="balanced"
  • Champion rows are intentionally duplicated in training to handle severe class imbalance
  • Saved model path: data_pipeline/models/random_forest_v1.pkl

Important Modeling Note

The core model predicts championship probability, not direct game-win probability. Matchup % shown in the UI is a transformed comparison of two team probabilities (see next section).


How Team-vs-Team Comparison Works

Backend logic:

  • backend/app/services/simulator.py

Flow:

  1. Load Team A + Team B stats for the effective season
  2. Apply slider adjustments to each team
  3. Recompute net_rating = off_rating - def_rating after adjustments
  4. Predict each team's championship probability via model.predict_proba
  5. Convert the two probabilities into matchup percentages using:
    • probability clipping floor/ceiling
    • log-odds conversion
    • temperature softening
    • blend toward 50/50 to avoid unrealistic extremes

This is why outputs are now more realistic (not hard 0%/100% in typical cases).


What the Sliders Mean

Frontend sends this payload:

{
  "team_a_id": 1610612738,
  "team_b_id": 1610612747,
  "adjustments": {
    "team_a_off_rating_pct": 10,
    "team_a_def_rating_pct": -5,
    "team_a_pace_pct": 5,
    "team_b_off_rating_pct": 0,
    "team_b_def_rating_pct": 0,
    "team_b_pace_pct": 0
  }
}

Interpretation:

  • off_rating_pct: % boost/penalty to offensive rating
  • def_rating_pct: % change to defensive rating (lower defensive rating is better)
  • pace_pct: % change to possessions/game pace

Impact:

  • Sliders directly alter model input features before inference
  • Every slider change triggers a debounced re-predict call
  • This lets you simulate hypothetical performance shifts and see probability movement instantly

Season Handling (2025-26 Support)

API season behavior:

  • backend/app/services/routes.py
  • Uses NBA_TARGET_SEASON if present in DB
  • Otherwise falls back to latest available season in team_season_stats
  • /api/predict returns the season field so UI/results are explicit

Data ingestion season behavior:

  • data_pipeline/scripts/fetch_nba_stats.py
  • Dynamic season generation using:
    • NBA_TARGET_SEASON (default inferred current NBA season)
    • NBA_START_YEAR (for range control)

Example (single-season refresh):

NBA_START_YEAR=2025 NBA_TARGET_SEASON=2025-26 python data_pipeline/scripts/fetch_nba_stats.py

Project Structure

Nbaplayoffs-main/
├── backend/
│   └── app/
│       ├── services/routes.py
│       ├── services/supabase.py
│       ├── services/simulator.py
│       └── main.py
├── data_pipeline/
│   ├── models/random_forest_v1.pkl
│   └── scripts/
│       ├── fetch_nba_stats.py
│       ├── train_model.py
│       └── predict_champion.py
└── frontend/
    └── src/
        ├── App.jsx
        ├── services/api.js
        └── components/

Tech Stack

Data + ML

  • Python
  • nba_api
  • pandas, numpy
  • scikit-learn
  • joblib

Backend

  • FastAPI
  • Uvicorn
  • Supabase Python client
  • python-dotenv

Frontend

  • React
  • Vite
  • Tailwind CSS
  • Axios
  • use-debounce

Data Store

  • Supabase (PostgreSQL)

API Endpoints

Base URL: http://127.0.0.1:8000

  • GET /
    Health check

  • GET /api/teams
    Returns teams for effective current season

  • GET /api/team/{team_id}/stats
    Returns one team's season stats

  • POST /api/predict
    Returns head-to-head matchup percentages + raw model probabilities

Interactive docs:

  • http://127.0.0.1:8000/docs

Local Run Instructions (Any Device)

Clone the repo and open it in your terminal/editor. All commands below are relative to the project root.

1) Backend

Create and activate a virtual environment:

macOS/Linux:

python3 -m venv venv
source venv/bin/activate

Windows (PowerShell):

python -m venv venv
.\venv\Scripts\Activate.ps1

Install backend dependencies and run API:

pip install fastapi uvicorn python-dotenv supabase joblib scikit-learn nba_api pandas
cd backend
uvicorn app.main:app --reload

2) Frontend

In a second terminal:

cd frontend
npm install
npm run dev

Open:

  • Frontend: http://localhost:5173
  • API docs: http://127.0.0.1:8000/docs

Data + Model Refresh Workflow

Pull/update stats into Supabase

# from project root, with venv activated
python data_pipeline/scripts/fetch_nba_stats.py

Retrain model

# from project root, with venv activated
python data_pipeline/scripts/train_model.py

Restart backend to load latest model

cd backend
uvicorn app.main:app --reload

Current Limitations

  • Matchup win % is derived from a championship model, not trained directly on game-level head-to-head outcomes
  • Results are regular-season-stat driven and may not capture injuries, rotations, fatigue, or playoff matchup schemes
  • Class imbalance is significant for championship labels, so probabilities should be treated as directional, not betting-grade certainty

Next Improvements

  • Train a dedicated game-level or series-level matchup model
  • Add injury and roster context features
  • Add model versioning and experiment tracking
  • Add unit/integration tests around prediction calibration
  • Add CI checks and deployment scripts for backend/frontend

Author

  • Param Patel
  • Email: parampatel2007@gmail.com

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages