Inspiration

Shooting percentage tells us what happened, but it leaves an important question unanswered: did a player or team perform better or worse than their shot situations would suggest?

ShotSense turns that question into an interactive tool. It helps coaches and analysts identify situations worth investigating through game film and deeper analysis.

What it does

ShotSense compares actual makes with expected makes from a transparent shot-make probability model.

Users can filter real NBA shots by team, player, season, zone, shot type, and period. The dashboard updates shooting percentages, shot locations, zone comparisons, and an investigation queue. Sample sizes and limitations stay visible, and situation tables can be downloaded.

The public dashboard runs in a browser without installation or sign-in.

How I built it

I used 218,701 real NBA shot attempts from the 2023–24 season, published by Vladislav Shufinskiy under Apache-2.0.

The analysis pipeline validates the dataset and trains a logistic regression using shot distance, zone, two- versus three-point type, and game period. Shot-clock time is unavailable, so it is omitted.

The first 80% of distinct game dates train the model, while later dates provide a held-out evaluation. No game appears in both samples, and preprocessing is fitted only on training data.

The full application uses Python, pandas, scikit-learn, Streamlit, and Altair. A public HTML, CSS, and JavaScript dashboard uses the same precomputed probabilities and is deployed through GitHub Pages.

Results

On 46,251 held-out shots, the model achieved a Brier score of 0.23210, compared with 0.24924 for a constant training shooting-percentage baseline. Lower Brier scores indicate better probability predictions.

The largest absolute zone residual was in the restricted area: 126.7 more makes than expected across 13,193 attempts, approximately +1.0 percentage point.

This is a lead for investigation—not proof of a repeatable advantage. Shooter mix, defensive pressure, and other omitted context could explain the difference.

Challenges

A key challenge was keeping the analysis honest and reproducible: verifying the dataset’s fields and license, preventing training/test leakage, and making sure filters updated every displayed calculation.

Another challenge was making the project accessible without requiring Python installation. The browser dashboard solves this while preserving the same held-out predictions used by the full application.

What I learned

Model evaluation and clear communication matter as much as the dashboard itself. A useful analytics tool should explain its baseline, expose its assumptions, and distinguish an interesting pattern from evidence strong enough to guide a decision.

ShotSense also demonstrates why shooting percentage alone is incomplete: shot context changes expectations, but even a contextual model leaves substantial uncertainty.

What’s next

I would validate the approach across additional seasons, investigate calibration across smaller groups, and incorporate richer context where reliable, appropriately licensed data is available.

A future version could compare expected points and possession outcomes rather than make probability alone.

Open source and attribution

ShotSense code is MIT licensed. The bundled dataset retains its separate Apache-2.0 license and attribution.

Data source: Vladislav Shufinskiy’s NBA dataset.

The project was built with Codex assistance. All 16 Python/UI tests and two browser-calculation tests passed, and GitHub CI and public deployment completed successfully.

Share this project:

Updates

Submission history