Sports Analytics · Causal Inference · Difference-in-Differences
Prompted by Thomas Tuchel's back-five switch in the England-Argentina 2026 World Cup semifinal: does bringing on a defender for an attacker or midfielder actually protect a lead, or does it just look that way in hindsight? 2,860 matches and 18,161 substitutions from StatsBomb's open data — top domestic leagues, both World Cups, both Euros, both Women's World Cups, Copa America 2024, AFCON 2023, two full FA Women's Super League seasons — matched against tens of thousands of "no substitution" control moments in the identical scoreline, time, and pressure situation.
Defender on for a midfielder or forward: goal difference -0.68 per 90, p=0.033 — a proven net cost, not just an absent benefit. The mirror image, attacker on for a defender or midfielder, is a proven net gain: +0.53, p=0.0066. The version that actually holds up as a defensive fix — forward off, midfielder on, back line untouched — shows a real drop in shots and goals conceded with no proven cost to attack.
Read the full write-up →
Python
Difference-in-Differences
Causal Inference
StatsBomb
Matched Controls
Pandas
Marketing Science · Sentiment Analysis · Stacked Event Study
Sentiment Around Shocking NBA Trades — A Stacked Event Study
Does a major trade reliably shift media sentiment, or does it just look that way for any one event? Daily Google News headlines for 3 major in-season trades — Luka Doncic to the Lakers, Kevin Durant to the Suns, James Harden to the Nets — scored with VADER and DistilBERT, compared before vs. after each trade individually and pooled. 3,204 headlines total.
Doncic alone: not significant. Durant alone: not significant. Harden alone: massive, p < 0.0001 — DistilBERT swings from -0.23 (trade-demand drama) to +0.22 (superteam analysis) the moment the trade happened. Pooled across all 3, the effect is real for both methods (VADER p=0.0025, DistilBERT p<0.0001). A single event didn't have the power to show what three, stacked, clearly do.
Read the full write-up →
Python
VADER
DistilBERT
Stacked Event Study
Welch's t-test
Pandas
Product DS · Recommender Systems · Similarity Search
Player Similarity Recommender — Premier League 2024-25
Can a "players like this" recommender find statistically similar players without ever being told what position they play? Cosine similarity on 23 per-90 stat features (incl. passing, creation, possession), indexed with FAISS, across 321 Premier League players (2024-25, 900+ minutes). Same architecture as "customers like this one" in marketing personalization.
Quantitative validation: top-5 matches share position 72.1% of the time vs. 34.3% random chance — a 2.10x lift, with no position label ever fed to the model. The real test was Kevin De Bruyne — a first pass with no passing data matched him to plain wingers. Adding real FBref passing/creation/possession stats (fetched past the library's public API limits) fixed it: Bukayo Saka, a genuine elite creator, now shows up at #2.
Read the full write-up →
Python
FAISS
Cosine Similarity
FBref
PCA
Scikit-learn
Marketing Science · Forecasting · Time Series
NBA Standings Forecasting — Baseline vs ARIMA (2014–2024)
Given mid-season data, which model better predicts a team's final win total? 240 team-seasons across 8 full 82-game NBA seasons, forecast from the halfway point, three ways: a pace-extrapolation baseline, ARIMA, and Pythagorean win expectation (scoring margin, not win-loss record) with leave-one-season-out regression.
ARIMA loses badly — RMSE 8.29 wins vs the baseline's 4.97, beating it in only 35.8% of team-seasons. Pythagorean wins outright: RMSE 4.47, beating the baseline in 60.4% of team-seasons. A paired t-test on matched per-team-season error confirms the gap is real (p = 0.0038), not sampling noise across 240 team-seasons.
Read the full write-up →
Python
ARIMA
Time Series
Statsmodels
nba_api
Forecasting
Marketing Science · Survival Analysis · Cox Regression
NBA Career Survival Analysis — When Do Players Decline? (1996–2025)
At what point in a career does decline become irreversible — and does it depend on position? Kaplan-Meier survival curves plus Cox Proportional Hazard regression on 1,757 NBA careers, 1996–2025. The same technique used to model customer churn timing, applied to careers instead of subscriptions.
Median career: 6.0 seasons. Position doesn't predict survival (log-rank p = 0.083) — power forwards actually last longest. One feature does: peak performance, HR 0.273 [0.250, 0.298]. Concordance 0.82 in-sample, 0.822 out-of-sample across 5 held-out splits — not overfit. But a Schoenfeld-residuals check flags peak performance as violating the model's core assumption (p = 2.6e-43): its effect on risk isn't actually constant across a career.
Read the full write-up →
Python
Survival Analysis
Kaplan-Meier
Cox Regression
lifelines
nba_api
Marketing Science · Propensity Modeling · Logistic Regression
World Cup Winner Propensity Model — 2026 Rankings (1990–2026)
Which teams have the profile of a World Cup winner? Binary classification applied to 35 years of World Cup data — the same technique marketing teams use to score leads. Train on historical converters. Score the current field. Rank by similarity to past winners. Nine positive labels in 240 team-tournament rows. 3.3% positive rate.
Train AUC 0.959. Test AUC 0.968 on the held-out 2022 field. Argentina ranked third at 15 percent in 2022. They won. Spain in 2026 ranks at 45 percent — the highest score since Spain themselves in 2010.
Read the full write-up →
Python
Logistic Regression
SHAP
Elo Ratings
Binary Classification
Scikit-learn
Marketing Science · LTV Modeling · Acquisition Channel Analysis
MLB Player LTV + CAC — Draft vs Free Agency vs Trade (1990–2015)
Can you predict a player's total career value from their first three seasons? Which acquisition channel offers the best LTV:CAC ratio? Gradient boosting regression applied to 25 years of MLB career data — the same payback curve logic used to evaluate paid acquisition channels in marketing.
Early-career WAR strongly predicts lifetime value. Draft picks return the highest LTV:CAC ratio across channels. The payback curve shows most players either earn back their cost within three seasons or never do.
Read the full write-up →
Python
Gradient Boosting
LTV Modeling
CAC Analysis
Pandas
Scikit-learn
Marketing Science · Churn Modeling · XGBoost
NBA Player Churn Model — Predicting Rotation Exits (2000–2026)
Which NBA players are about to churn out of a team's rotation? XGBoost binary classifier trained on usage rate, age, contract year status, and performance trends — the same early warning signals used in customer churn models. SHAP explainability identifies which features drive each prediction.
XGBoost outperforms logistic regression baseline. Minutes decline rate is the single strongest early warning signal — more predictive than age, position, or team record.
Read the full write-up →
Python
XGBoost
SHAP
Logistic Regression
nba_api
Binary Classification
Marketing Science · Cohort Analysis · Survival Modelling
NBA Draft Class Cohort Analysis — 30 Years of Retention and LTV (1996–2026)
Every growth team builds the same table: users by signup month, % still active at month 1, 3, 6, 12. I built one for 30 years of NBA drafts. Each draft year is a cohort. Each career year is a time period. The cell value is the % of that class still playing meaningful minutes. Same logic, different labels.
ANOVA across 23 cohorts is significant at p < 0.001 — draft class differences are statistically real. Average retention drops to 49% by career year 5 and 30% by year 10. Top-5 picks reach year 10 at 2.8x the rate of second-rounders (55.7% vs 19.9%). The 2003 class — LeBron, Carmelo, Wade, Bosh — is a genuine outlier at 1.4x the 19-class average LTV.
Read the full write-up →
Python
Cohort Analysis
Survival Analysis
ANOVA
Pandas
nba_api
Marketing Science · Funnel Analysis · Statistical Testing
Premier League Fan Funnel — Instagram to Season Tickets (2023-24)
Where do sports fans drop off on their journey from digital follower to committed season ticket holder? A three-stage funnel built from citable published sources only: 20 clubs, Instagram following from official profiles, PL official attendance figures, and season ticket holder counts from Companies House annual reports. No proxies, no assumptions.
Instagram to STH conversion is strongly negatively correlated with follower count (Pearson r = -0.631, p = 0.003). Non-Big-Six clubs convert 9.2x more of their digital audience into season ticket holders than the Big Six. The gap is a supply constraint, not weak demand. Sheffield United converts 2.86% of Instagram followers into STH. Liverpool converts 0.07%. That is a 41x difference.
Read the full write-up →
Python
Funnel Analysis
Pearson Correlation
Chi-square
Plotly
Pandas
Marketing Science · Customer Segmentation · Dimensionality Reduction
NBA Player Archetype Segmentation — Three Eras (2003–2026)
Do traditional basketball positions capture how players actually play — or are there natural statistical archetypes telling a different story? K-Means clustering on NBA advanced stats (USG%, AST%, REB%, TS%, and more) across three era windows, using the same behavioral segmentation techniques applied to customer data in Marketing.
K was selected independently per era using silhouette scoring. The modern era required K=5 — the model independently carved out a Pass-First Guard cluster (high AST, low USG) that didn't exist in either prior era. Find the breakdown below.
Read the full write-up →
3-and-D / Role Player
Ball-Dominant Playmaker
Glass Anchor
Scoring Big / PF
Pass-First Guard (Modern)
Python
K-Means
UMAP
PCA
Scikit-learn
nba_api
Sports Analytics · Predictive Modeling
End-to-end ML pipeline for rugby match prediction across 25,000+ games (1893–2026). Features engineered on ELO differentials, form, momentum, head-to-head history, rest days, margin form, and venue-specific win rates. XGBoost and Logistic Regression trained in a walk-forward backtest — training on all data before year T, predicting year T.
Backtested against real bookmaker odds (Pinnacle/bet365). Model achieves 71% accuracy vs 69% ELO baseline — but real-odds ROI is negative, consistent with an efficient market that has already priced in publicly available information.
Read the full write-up →
Could not load feature data.
Could not load accuracy data.
Python
XGBoost
Logistic Regression
Backtesting
Plotly
Feature Engineering
Sports Analytics · Published Research · Interactive Dashboard
Elo-based rating system for international rugby union. Processes 25,000+ international matches from 1893 to present with adaptive K-factors, home advantage corrections, and recency weighting. Produces pre-match win probabilities calibrated against market odds.
Extended into a Streamlit dashboard with six analytical views: current rankings, historical ELO trajectories, era dominance across five periods (pre-WW1 through modern), greatest upsets by upset probability, a live match predictor, and expected vs actual wins. Notable finding: New Zealand 2013 outperformed expected wins by 6.7.
Could not load rankings data.
Could not load World Rugby data.
Python
Elo Ratings
Statistical Modeling
Streamlit
Plotly
Published Research
Computer Vision · Reinforcement Learning
Six-stage pipeline processing match footage into structured game data. YOLOv8 detects players and ball frame-by-frame; K-means clusters jersey colors to auto-assign team membership; homography calibration maps pixel positions to field coordinates. Persistent player IDs are tracked across frames with velocity and possession computed between detections.
Labeled events — passes, carries, kicks, tries, turnovers — are used to assign rewards and train a PyTorch actor network for in-game decision classification.
Python
YOLOv8
PyTorch
Computer Vision
Reinforcement Learning
OpenCV