Model Card
About This Model
What the model actually does, what it assumes, and where it's weak — written to be checked against the code, not to sell it. See the source, the track record for current accuracy against a naive baseline, and the debugging log for the real bugs this went through before publishing.
What data the model uses
Everything comes from FastF1, which wraps the official F1 timing data and the Ergast historical database. Per driver, per round, that's:
- Qualifying pace — grid position (real, once qualifying has run; projected from season-average pace before that) and speed-trap top speed from the last 8 completed rounds.
- Championship standings — live points total through the most recent round, pulled via
fastf1.ergast. - Historical results at this circuit — finishing position for 2019–2025 (fewer years, or none, for a circuit new to the calendar).
- Tire degradation — lap-time-vs-tyre-life slope from FP2 long runs once they exist, else a season-average slope from the last 8 rounds.
- Pit-stop performance — in-lap + out-lap time minus that driver's best clean lap, averaged across the season.
- Rain probability — the fraction of that circuit's races since 2019 that saw any rainfall (a historical base rate, not a live weather forecast — see Limitations).
Each of those becomes a 0–1 percentile among the current grid before it enters the model, so the underlying units (seconds, points, km/h) never mix directly — only their relative rank does.
Key assumptions
- The per-feature weights are hand-tuned, not fit. Quali pace, points, grid position, top speed, tire management, historical form, and pit stops are combined into one race-pace score with fixed weights (e.g. quali pace 0.25, championship points 0.26) chosen so a clear form leader wins a believable 25–35% of simulations rather than 80%+. That tuning target was a judgment call about plausibility, not a fit against held-out results.
- Circuit character (overtaking difficulty, downforce level, tire severity) is a hand-set 0–1 estimate per track, not derived from this project's own overtake or lap data — that would need years of telemetry this project doesn't have. If a track's number looks wrong, the fix is editing that row, not the formula consuming it.
- Race-day variance is a single noise term added to each driver's score per simulation, scaled up for closely-matched midpack cars and for rain — not a simulation of specific race events (see Limitations).
- A driver's current team is whoever raced for them last round, reconciled against the real qualifying entry list once that exists for the round being predicted. Before qualifying, a substitution that's already reverting has to be corrected by hand (see
GRID_OVERRIDE_BY_ROUNDinrace_model.py) — there's no live roster feed.
Known limitations
- No safety car, VSC, or red-flag modeling. These reshuffle real races constantly — closing gaps, changing strategy windows, occasionally ending a leader's race outright — and this model has no signal for any of it. It only knows a driver's pace, not what happens to everyone else around them mid-race.
- Small sample size, especially per circuit. At most 7 years of historical results per track (fewer for a new circuit), and the model's own graded track record is still small — see the track record page for the current count and whether it's actually beating the naive always-bet-the-polesitter baseline. Early on, a handful of races is not enough signal to call that either way with confidence.
- Tire degradation is a genuinely noisy signal — raw lap-time-vs-tyre-life slopes are tiny (~0.01–0.05s/lap over ~20 stints) and not corrected for the fuel-burn effect that dominates that range. It's kept at a small weight everywhere for exactly this reason, but a small weight on noise is still noise, not signal.
- Rain probability is a historical base rate, not a forecast. It reflects how often that circuit has been wet since 2019, not this weekend's actual weather — a live forecast integration would clearly beat this close to race day.
- No compound-specific tire modeling, no strategy simulation, no team orders. Degradation is one slope per driver regardless of compound; the model doesn't simulate pit windows, undercuts, or a team favoring one driver over another.
- Depends on FastF1's own data quality. FastF1 fuzzy-matches session names and doesn't error on a circuit that wasn't on a given year's calendar — silently substituting the closest-named race instead (documented in the debugging log). That's guarded against for historical lookups, but it's a real fragility in the underlying data source, not something this project controls.
What I'd improve with more time or data
- Fit the feature weights against held-out historical races instead of hand-tuning them to a plausible-looking win-probability spread — the current tuning target ("doesn't look absurd") is a much weaker bar than "minimizes Brier score on data the fit never saw."
- Model safety car / VSC probability per circuit from historical race data — the same kind of per-circuit profile this project already builds for overtaking difficulty, just for incident rate instead.
- Use the actual qualifying gap to pole (continuous, in seconds) instead of just percentile rank — order alone throws away how much faster P1 was than P2.
- Swap the historical wet-race base rate for a real weather forecast once one's available close to race day.
- Automate the mid-season driver-lineup correction with a live entry-list feed instead of a manually maintained override table.
- Most of all: let the track record grow. Every point above is a hypothesis about what would help — the only way to know for sure is more graded races against the baseline this model is supposed to beat.