Python 3 (ipykernel)
NBA Match Predictor
An end-to-end pipeline that scrapes five NBA seasons, turns raw box scores into 200+ "form going into the game" features, and trains an XGBoost model to predict who wins.
- Python
- Scrapy
- pandas
- scikit-learn
- XGBoost
In [1]:
nba.plot_momentum()Out[1]:
Momentum is real: teams on a longer streak win more often.
In [2]:
nba.summary()Out[2]:
- seasons
- 2021 – 2025
- games
- 6,000+ scraped from basketball-reference.com
- raw_stats
- ~40 per player, per game
- features
- 200+ per matchup
- model
- XGBoost classifier
- validation
- 5-fold time-series cross-validation
How it works
- Scrape the data
- A Scrapy crawler collects every game result and every player's stat line for five seasons.
- Roll players up into teams
- Each team's game is the average of its players' stats, weighted by minutes played, so starters count more than the bench.
- Engineer features
- For each matchup, describe how both teams were playing coming into the game:
- recent shooting, rebounding and turnovers over different windows
- win streaks and days of rest
- head-to-head differences, such as one team's offense against the other's defense
- For each matchup, describe how both teams were playing coming into the game:
- Train the model
- XGBoost predicts whether the home team wins.
In [3]:
model.plot_top_features(20)Out[3]:
Streaks lead, followed by recent rebounding and shooting form.
Takeaways
- Getting the data right matters more than the model. Most of the work, and most of the bugs, were in scraping, cleaning and building leak-free features.
- At first I shuffled the games before splitting them, which caused data leakage: the model was trained on games played after the ones it was tested on, so it learned from the future. Now it always trains on earlier games and tests on later ones, and every feature is built only from games played before the matchup.
- Single games are noisy. Momentum and rest carry real signal, but box-score form only goes so far.
- Next, I'd add schedule context (travel, start times, overtime) and injury and lineup data.