International Results Datasets

Overview

The v1 model trains on two free GitHub CSV datasets (both named in the project intake):

  • github.com/martj42/international_results — every men's full international since 1872 (~48k matches, growing). One row per match: date, home_team, away_team, home_score, away_score, tournament, city, country, neutral. Companion files add goalscorers and penalty-shootout winners. Community-maintained, updated within days of matchdays.
  • github.com/jfjelstul/worldcup — a relational database of World Cup history (1930–2022) in ~25 linked CSVs: matches, squads, lineups, goals, bookings, substitutions, referees, stadiums. Academic-grade, with stable IDs.

Division of labour: martj42 is the training corpus (full international match graph, the only way to estimate current team strengths); jfjelstul is the backtesting and enrichment corpus (per-tournament detail for validating against 2010–2022 World Cups, lineups for any future player-level work).

Why It Matters

These two files are the entire upstream of the v1 model — every λ the Poisson produces traces back to preprocessing decisions made here. The datasets are clean by hobby-data standards but have structural traps that silently bias a model if unhandled.

Key fields and traps (martj42)

  • neutral flag — TRUE means neither side is at home; home_team is then just the first-listed team. This flag is what gates the home-advantage term in fitting-poisson-mle. Roughly a quarter of all matches are neutral, and nearly all World Cup matches are.
  • tournament — free-text competition name ("FIFA World Cup", "FIFA World Cup qualification", "Friendly", ~150 distinct values). You must map these to importance weights yourself (see international-football-modelling); build the mapping table once and version it.
  • Country identity drift — teams appear under historical names: USSR (until 1991) then Russia; Yugoslavia → Serbia and Montenegro → Serbia; West Germany → Germany (East Germany ends 1990); Czechoslovakia → Czech Republic/Czechia and Slovakia; Zaire → DR Congo. Decide successor mappings explicitly. Common choice: map the primary successor (USSR→Russia, West Germany→Germany, Czechoslovakia→Czechia, Yugoslavia→Serbia) and drop dissolved siblings' pre-split history for the non-successor. With sensible time decay this matters less — most pre-1992 weight is near zero anyway.
  • Name normalization across datasets — martj42, jfjelstul, API-Football, and odds feeds all spell teams differently ("South Korea" / "Korea Republic" / "Korea, South"; "USA" / "United States"; "Ivory Coast" / "Côte d'Ivoire"). Build one canonical-name table at the start; every join bug downstream is cheaper to prevent here.
  • Score semantics — scores are after 90 minutes plus extra time if played, excluding penalty shootouts (the shootouts.csv companion records those separately). So knockout draws decided on penalties correctly appear as draws — which is what a 90-minute-ish model wants, but note ET goals are baked in for those matches (a small contamination of the 90-minute assumption; ignorable for v1).
  • Non-FIFA members — the data includes micronations and non-FIFA sides; harmless if shrinkage is in place, or filter to FIFA members to shrink the parameter count.
  • Include all match types, with friendlies down-weighted rather than excluded (they're most of the inter-confederation signal)
  • Time window: include everything, let exponential decay handle relevance — but cap at ~1990+ to dodge most country-identity issues at near-zero cost
  • Keep all inter-confederation matches regardless of age — they anchor the confederation offsets (international-football-modelling)
  • Exclude nothing by venue; the neutral flag handles it

Pitfalls

  • Treating home_team as meaningful at neutral venues — learns a phantom first-listed-team advantage
  • Joining datasets on raw names — silent row drops; always join through the canonical table and assert match counts
  • Backtesting leakage — when validating on the 2018 World Cup, fit decay weights/importance weights using data up to June 2018 only (walk-forward-validation); refitting hyperparameters on the full corpus leaks
  • Assuming the repo is static — martj42 updates continuously during the tournament; pin a commit hash per model run for reproducibility
  • No shot/xG data anywhere here — neither dataset has event data; player-level or xG extensions need StatsBomb open data (free for WC 2018/2022) or paid feeds

See Also