|
| 1 | +# Spike O0 — third-observer source audit (Transfermarkt) |
| 2 | + |
| 3 | +> 2026-07-06. Verdict: **GO**. Source: `dcaribou/transfermarkt-datasets` |
| 4 | +> (Kaggle mirror `davidcariboo/player-scores`), **CC0-1.0** (public domain), |
| 5 | +> weekly refresh, OSS pipeline. Direct download, **no account needed**: |
| 6 | +> `https://pub-e682421888d945d684bcae8890b0ec20.r2.dev/data/transfermarkt-datasets.duckdb` |
| 7 | +> (~200 MB DuckDB; keep in `data/`, gitignored — same posture as every raw dump). |
| 8 | +
|
| 9 | +## Coverage |
| 10 | + |
| 11 | +- **Games:** 88,943 across 70 competitions, seasons 2005–2025; dense from 2012. |
| 12 | +- **Lineups (`game_lineups`):** usable from **2013** — ≥95% of games carry a full |
| 13 | + starting XI per side from 2013-14 onward. This sets the evaluation era. |
| 14 | +- **Valuations (`player_valuations`):** 400k+ rows, dense from ~2011; |
| 15 | + 20k+ players covered per recent year. |
| 16 | +- **Scope caveat:** **first tiers only** (31 domestic leagues). None of our |
| 17 | + second/third tiers (E1–E3, EC, SP2, I2, F2, D2, SC1–SC3) nor IRL/FIN/CHN. |
| 18 | + |
| 19 | +## Join vs the frozen archive (matches.csv, 2013+) |
| 20 | + |
| 21 | +24 of our 38 divisions map to a TM first tier (`DIV2COMP` below) = **84,091 |
| 22 | +frozen matches** in the lineup era. Naive-normalised name match rates: |
| 23 | + |
| 24 | +- **79–100%**: E0, SP1, I1 (100%), F1, D1, N1, P1, B1, T1, G1, SC0, USA, DEN, SUI |
| 25 | + → a small hand-curated mapping table (the `fdcanon.py` precedent) closes these |
| 26 | + to ~100%. |
| 27 | +- **28–73%** (ARG, BRA, JAP, MEX, RUS, SWE, NOR, POL, ROM, AUT): mostly an |
| 28 | + artifact — `clubs.domestic_competition_id` reflects *current* membership, so |
| 29 | + relegated clubs drop out of the per-league pool (e.g. RO1 shows 19 clubs vs |
| 30 | + 40 frozen teams). **O1 must match against the full `clubs` table**, league |
| 31 | + used only as a tiebreaker. |
| 32 | + |
| 33 | +Realistic O2 sample: the ~14 strong divisions ≈ **45–50k matches** — far above |
| 34 | +the per-bucket noise floor (SE(skew) ≈ 0.1 needs ~500/bucket). |
| 35 | + |
| 36 | +## End-to-end sanity |
| 37 | + |
| 38 | +Starting-lineup market value at match date via |
| 39 | +`game_lineups → player_valuations` (latest valuation ≤ match date): |
| 40 | +Man City **€799M** vs Newcastle **€398M** (2023-08-19), 22/22 starters valued. |
| 41 | + |
| 42 | +## O3 hook (World Cup) |
| 43 | + |
| 44 | +`national_teams` (124 teams) carries `total_market_value` + `fifa_ranking` |
| 45 | +directly — the prospective third `p` column for the WC ledger needs no squad |
| 46 | +reconstruction for *current* values. Historical national squads would need |
| 47 | +Wikipedia squad lists + player join (only if we backtest past WCs). |
| 48 | + |
| 49 | +## DIV2COMP (frozen division → TM competition) |
| 50 | + |
| 51 | +```python |
| 52 | +DIV2COMP = {'E0':'GB1','SP1':'ES1','I1':'IT1','F1':'FR1','D1':'L1','N1':'NL1', |
| 53 | + 'P1':'PO1','B1':'BE1','T1':'TR1','G1':'GR1','SC0':'SC1','ARG':'ARG1', |
| 54 | + 'USA':'MLS1','BRA':'BRA1','JAP':'JAP1','MEX':'MEX1','RUS':'RU1','DEN':'DK1', |
| 55 | + 'SWE':'SE1','NOR':'NO1','POL':'PL1','ROM':'RO1','SUI':'C1','AUT':'A1'} |
| 56 | +``` |
| 57 | + |
| 58 | +## Decisions fixed for O1 |
| 59 | + |
| 60 | +1. **State = log matchday starting-lineup market value** (coverage confirmed); |
| 61 | + season squad value only as fallback for pre-2013 or missing lineups. |
| 62 | +2. **Evaluation era 2013+**; link (ordered probit) trained on an earlier, |
| 63 | + disjoint slice of the era split — exact split decided in O1. |
| 64 | +3. Match clubs globally (not per-league); commit the curated name map, |
| 65 | + never the raw dump. |
0 commit comments