Sports Dashboard

MI Bivariate Poisson + Dixon-Coles + Elo

← Back to Blog
|Research

FootyStats xG Is 3x Worse Than Shots on Target: The Data Quality Crisis We Fixed

FootyStats xG has corr=0.35 with goals — beaten by SoT×0.32 (corr=0.56) in ALL 20 non-Big-5 leagues. But for regression detection, noise is a feature: FootyStats xG (62.7% regression) beats our precise aggregate model (58%). The variance filter needs process, not outcome.

The Question

We use FootyStats xG for 20 non-Big-5 leagues. Is it any good? And what are our alternatives?

What We Found

FootyStats xG is actively harmful. In every single non-Big-5 league (20/20 tested), a crude shots_on_target × 0.32 formula predicts actual goals better than FootyStats' xG model.

LeagueFootyStats xG→Goals CorrSoT×0.32→Goals CorrImprovement
Championship0.3490.589+68%
Serie B0.2090.544+160%
Bundesliga 20.2590.549+112%
Eredivisie0.3940.640+62%
Brazil A0.2060.437+112%
Argentina0.2360.484+105%
+ 14 moreall worseall better+23% to +160%

FootyStats and FotMob are literally the same data (RMSE identical to 5 decimal places). Same match, same numbers — likely the same underlying provider.

The worst part: The code has a fallback (SOT_TO_XG = 0.32 in data-prep.ts line 507) that's 3x better, but FootyStats xG files OVERRIDE it in the loading priority. We were choosing the worse signal because it had a fancier name.

The Nuance

BUT — FootyStats xG works better for regression detection. This is the session's most important discovery. For the variance filter:

SourceGoal Prediction CorrRegression Rate
Our aggregate model0.67 (BEST)58.0% (WORST)
FootyStats xG0.35 (WORST)62.7% (MIDDLE)
Understat xG0.6368.3% (BEST)
FotMob match-level0.3593.8% (BEST on strict test)

Noise is a feature. FootyStats xG is "bad" at predicting goals but "good" at regression detection because its errors are independent of finishing luck. When actual goals diverge from FootyStats xG, the gap is more likely to be real overperformance than measurement error.

What This Means

Do NOT replace FootyStats xG with a more accurate model for the variance filter. We tried this with our aggregate model (corr 0.67) — it has 58% regression rate, worse than FootyStats' 62.7%. Making xG more accurate REDUCES the regression signal.

Do replace FootyStats xG for DISPLAY purposes. Our aggregate v2 model (corr 0.68 home / 0.67 away) gives more credible numbers on /picks.

The production data hierarchy for the variance filter:

  • Big 5: Understat xG (68.3% regression rate)
  • Non-Big-5: FotMob match-level xG (62.7-93.8% depending on methodology)
  • Fallback: SoT × 0.32 (better than FootyStats but worse than FotMob match-level)

What's Next

FotMob shot-level xG (from the page scraping pipeline) achieves 82.1% regression rate for non-Big-5 — better than match-level. But the marginal ROI improvement is only +0.1%. The existing match-level variance filter already catches the same teams at scale. Shot data's value is in derivative signals (multi-source disagreement, set-piece breakdown), not direct replacement.