CoolFace
Datasetpublic

lathise/table-tennis-pre-match-elo-ratings

Table Tennis Pre-Match Elo Ratings (sample) 2,000 table tennis matches where every row carries the Elo ratings of both players as they stood before the match was played, together with the model's pre-match win probability. No look-ahead leakage: the rating columns are frozen at the state that existed before the result was known, so the file is usable in a backtest exactly as shipped. Why this exists Match results are easy to scrape. What is hard is knowing what… See the full description on the dataset page: https://huggingface.co/datasets/lathise/table-tennis-pre-match-elo-ratings.

sourceHugging Facecc-by-4.0updated 1mo agoView on Hugging Face
1likes81downloads
Dataset Card

Table Tennis Pre-Match Elo Ratings (sample)

2,000 table tennis matches where every row carries the Elo ratings of both players as they stood before the match was played, together with the model's pre-match win probability.

No look-ahead leakage: the rating columns are frozen at the state that existed before the result was known, so the file is usable in a backtest exactly as shipped.

Why this exists

Match results are easy to scrape. What is hard is knowing what each player's strength looked like on the morning of the match — the only version of a rating you can legally use in a backtest. Build it yourself and you spend a week on the rating engine and another week discovering your first attempts leaked future information into the past.

Columns

ColumnTypeMeaning
match_idstringOpaque match id, unique
datedateMatch day, YYYY-MM-DD
leaguestringCompetition name
player_a, player_bstringOpaque, stable player ids
elo_a_pre, elo_b_prefloatElo before the match
sol_a_pre, sol_b_prefloatSolidity index before the match — share of wins by 2+ sets
p_modelfloatModel probability that A wins, computed pre-match
winnerA / BActual winner
sets_a, sets_bintSet score

The model

Elo computed at the set level rather than the match level: updated once per set, weighted by the point margin within that set. A 3–0 and a 3–2 are the same result to a match-level Elo; they are plainly not the same performance.

The match probability is derived from the set rating, then adjusted by a solidity differential with weights learned by logistic regression.

Is it calibrated?

That is the only question that matters for a probabilistic forecast, so here is the answer measured on the full 51,397-match dataset (49,353 rows once cold-start matches are excluded):

Model saidMatchesActually wonGap
50–55%22,53651.7%−0.8
55–60%14,30154.7%−2.8
60–65%7,08059.6%−2.9
65–70%3,00666.4%−1.1
70–75%1,33871.5%−1.0
75–80%63078.4%+0.9
80%+46282.0%—

Every bounded band lands within 2.9 points of its stated confidence.

Scoring on the full file: Brier 0.2435 against 0.2500 for a flat 50/50 baseline. On a clean 13,892-match holdout never used for fitting, the set-level model scores 0.2428 against 0.2480 for a match-level Elo at K=32.

Reproduce it on this sample

python
import pandas as pd, numpy as np

m = pd.read_csv("tt_ratings_sample_2000.csv")
y = (m.winner == "A").astype(int)

print(((m.p_model - y) ** 2).mean())   # 0.2422  the model
print(((0.5       - y) ** 2).mean())   # 0.2500  always 50/50

Bucket by confidence and you will find 6 of 7 bands statistically consistent with perfect calibration on this sample (Wilson 95% intervals); the seventh holds too few matches to distinguish either way.

Honest limits

  • —The full dataset covers 25 June to 20 August 2026 — two months, 69 competitions, of which four are 95.6% of the file (TT Elite Series, Setka Cup, Czech Liga Pro, TT Cup). It is not a multi-season archive.
  • —1.2% of the full file are cold-start rows where both players sit at the opening 1500 rating. They are excluded from this sample.
  • —The edge over a match-level Elo at K=32 is +0.0052 Brier on the holdout. The methodology also shows K=32 is not that baseline's optimum, so the edge over a fully tuned match-level Elo is smaller and is not quantified. This is a well-built input to a model, not an edge in a box.
  • —Documentation and CSV column names are in French. The data itself is language-neutral: ISO dates, English league names, A/B winner flags.

The full dataset

51,397 matches, 1,662 players with ratings and solidity, weekly rating trajectories, and the calibration table, plus the data dictionary and the full methodology including what was tried and rejected (Glicko-2, at 0.2540).

Rebuilt and republished every 10 days, larger each time.

→ https://lathiselam.gumroad.com/l/tt-ratings

Elsewhere

License

This 2,000-row sample is released under CC BY 4.0 — free to use, including commercially, with attribution. The full dataset ships under a separate single-user commercial license.