Skip to content
james_tavita

~/projects/premier-league-match-forecasting

Premier League Match Forecasting: Baselines, Challengers, and a Shipped iOS App

Predicting a Premier League match outcome (home win / draw / away win) is a decades-old actuarial problem with a low ceiling — bookmakers and simple rating systems already capture most of the signal. The real question wasn't whether a model could predict outcomes, but whether a more sophisticated model (gradient-boosted trees on rich player and team features) actually beats well-understood baselines like Elo and Dixon-Coles, and whether the whole system could be shipped as a product fans could query directly.

Production ~/projects
01// problem.md

Problem

Predicting a Premier League match outcome (home win / draw / away win) is a decades-old actuarial problem with a low ceiling — bookmakers and simple rating systems already capture most of the signal. The real question wasn't whether a model could predict outcomes, but whether a more sophisticated model (gradient-boosted trees on rich player and team features) actually beats well-understood baselines like Elo and Dixon-Coles, and whether the whole system could be shipped as a product fans could query directly.

02// decision.md

Decision Supported

Which forecasting approach (naive, Elo, Dixon-Coles, or an ML challenger) is trustworthy enough to surface as a probability estimate inside a consumer product, and which natural-language statistical questions the underlying database can answer with confidence versus should decline.

03// dataset.md

Dataset

A self-built database covering every Premier League match and season since the competition began: 34 seasons (1992–93 through 2025–26), 13,166 matches, 4,625 players, and 51 clubs. Each player-match is tracked as its own row — 346,764 in total — carrying a common set of observables (minutes played, goals, assists, shots, shots on target, tackles won, interceptions, cards, fouls, crosses, saves) across the full 34-season history. For the 26 most recent seasons (2000–01 onward), that set is extended to 58 tracked observables per player-match, adding xG, npxG, progressive passes/carries, pressures, shot- and goal-creating actions, PSxG, aerial duels, and more. Coverage completeness is tracked per season and per statistic rather than assumed.

04// architecture.md

Architecture

Two baseline forecasters — Elo ratings, and Dixon-Coles bivariate Poisson (both a simplified and a fully-parameterized version with time decay and a home-advantage term) — evaluated against a naive persistence baseline. Two LightGBM "challenger" model families (a residual-correction model trained on the baseline's errors, and a direct model trained on raw features) were built on a dedicated feature pipeline drawing on the 58-column player-match stats plus engineered lineup-availability and player-form-snapshot features. A separate player-profile-based in-play model estimates outcome probabilities using a two-term CDF-squared scoring approach. An unsupervised layer applies PCA + K-Means to per-90 stats (pressures, progressive actions, tackles, dribbles, shots, key passes, aerial duels) to cluster players into 5 style archetypes. A "residual discovery" research module runs elastic net, mutual information, and (sparse) PCA feature-selection sweeps hunting for predictive signal beyond the baselines, gated by negative-control checks and seasonal-stability tests before any feature is accepted.

05// baseline.md

Baseline

A naive persistence baseline (league-wide historical outcome frequency) sits under everything, with Elo and Dixon-Coles as the credible baselines every challenger model actually has to beat.

06// evaluation.md

Evaluation Framework

A true walk-forward backtest, not a random split: for each of 21 season-folds (2003–04 through 2023–24), train only on seasons before the fold and test on the ~380 held-out matches of that Premier League season — an expanding window that never lets a model see its own future. Scored on accuracy, Brier score, log-loss, Ranked Probability Score (RPS, the standard soccer-forecasting metric), and calibration error, with bootstrapped confidence intervals on the full Dixon-Coles model.

07// results.md

Results

Averaged across all 21 walk-forward folds: Elo reached 54.1% accuracy and RPS 0.198, Dixon-Coles 53.1% accuracy and RPS 0.201 — both clearly ahead of the naive baseline's 45.6% accuracy and RPS 0.229. The PCA/K-Means layer cleanly separated 5 recognizable player archetypes from 7 per-90 style features across the advanced-stats era of the database.

08// error_analysis.md

Error Analysis

Two honest negative results survived scrutiny rather than being discarded. First: the LightGBM challengers, evaluated on the identical 21-fold walk-forward protocol, did not beat the baseline — average RPS 0.209 (residual-correction) and 0.217 (direct) versus 0.200 for the baseline they were meant to improve on, and accuracy actually dropped (51.0% and 49.4% vs. 53.2%). More features and a more flexible model made forecasts worse, not better. Second: the player-profile in-play model, evaluated on 6,460 matches across 17 seasons, reached 54.1% overall accuracy but with a stark asymmetry — 81.0% accuracy on home wins against just 0.4% on draws — the model essentially never predicts a draw, a well-documented failure mode in soccer forecasting that's visible here rather than hidden behind an aggregate accuracy number.

09// deployment.md

Deployment Considerations

Shipped as "Premier Stats," a production iOS app (five iterated versions) with an iMessage extension, submitted to the App Store. It lets fans ask natural-language questions about players, clubs, matches, and lineups, and view match probability estimates where coverage supports it; unsupported or ambiguous questions return a refinement prompt instead of an invented answer, and probabilities are explicitly labeled as estimates rather than guarantees. A statistical query API (iterated through 12 versions) and a dedicated prediction API back the app; a live-data ingestion pipeline feeds in-play state.

10// monitoring.md

Monitoring Approach

No continuous production monitoring of forecast accuracy yet; the walk-forward backtest is re-run as new seasons complete, which is the main signal for whether Elo/Dixon-Coles calibration is drifting. Every research analysis (residual discovery, feature acceptance, model promotion) is preregistered before it's run — the hypothesis, method, and acceptance criteria are written down first, with amendments logged if scope changes — and gated by an acceptance-audit step before a model or feature is promoted, closer to a clinical-trial protocol than a typical side-project workflow.

11// limitations.md

Limitations

The two LightGBM challenger models underperformed the simpler Elo/Dixon-Coles baselines on identical held-out data — evidence that, for this dataset and feature set, added model complexity didn't translate into forecasting skill, and the baselines remain what's actually deployed.

Draw prediction is a persistent weak point (0.4% accuracy on actual draws in the in-play evaluation) — a known structural issue in soccer forecasting that no model variant here has solved.

Coverage isn't uniform across the 34-season history: the pre-2000 seasons carry only the common ~11-observable set (no xG, no advanced tracking stats), so any feature or model that depends on the 58-column advanced tier is implicitly restricted to the 26 most recent seasons — the self-tracked coverage table exists specifically because this can't be assumed away.

The residual-discovery module found several statistically "significant" feature candidates that failed seasonal-stability or negative-control checks and were rejected — worth stating explicitly, since a pass without those checks would have accepted spurious features.