Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

f1-predictor

A retro terminal app that predicts Formula 1 race finishing order and championship outcomes, with all ML running on your machine. Rust + ratatui TUI, XGBoost → ONNX models, optional local-LLM explanations via Ollama.

▐▛ F1 PREDICTOR ▜▌  RACES  SEASON   «2026»
╔ R09 BRITISH GRAND PRIX ── ORDER: RACE RESULT ── ρ 0.671 ═════════════╗
║ PRED  NO   DRIVER                 TEAM        GRID  SCORE  ACT   Δ   ║
║ P1    NOR  Lando Norris           McLaren      1    3.12   P1    ●   ║
║ P2    VER  Max Verstappen         Red Bull     3    4.81   P2    ●   ║
...

The prediction table sorts by whatever is most informative for that race — finished: actual result (green) · quali done: grid order (cyan) · before quali: the model's predicted order (amber). The title says which.

Live races: during a Grand Prix / sprint the app tails the free F1 live timing feed (livetiming.formula1.com, unofficial) and the table becomes a live view: rows ordered by a continuously updated estimate of the FINAL finishing order (model prediction blended toward track position as laps run out), plus current position, tyre changes so far, and an estimated next tyre-change lap per driver. No setup needed; if the feed is unreachable the app just falls back to the normal prediction view.

Quick start

git clone https://github.com/theabecaster/f1-predictor && cd f1-predictor
make setup     # installs rust + uv + libomp if missing, syncs python deps
make data      # downloads 2014-present history from the Jolpica API (~5 min)
make run       # launches the TUI (trained models ship with the repo)

Optional — natural-language explanations (press e on any driver):

# install Ollama from https://ollama.com/download, then:
make ollama    # pulls a local model (qwen3.5:27b-mlx / gemma4 / llama3.2)

No API keys, no accounts. Data comes from the free Jolpica F1 API (the Ergast successor); inference is local ONNX; the LLM is local Ollama and purely decorative — predictions never depend on it.

What it does

  • Race predictions — full finishing-order forecast for any race, past or upcoming. Past races show predicted-vs-actual with per-race Spearman ρ.
  • Two models, honestly separated:
    • race model — used once Saturday qualifying exists (grid position + quali-pace gap are the strongest predictors in the literature)
    • pre-quali model — used before qualifying; trained WITHOUT grid/quali features, so early-week forecasts are real form-based predictions, not a model fed placeholder grids
  • Championship forecasts (3 key) — Monte Carlo simulation of the rest of the season (10,000 runs): WDC and WCC title probabilities, top-3 odds, and projected final points. The pre-quali model is re-run for every remaining round, so circuit history varies driver strength track by track. Noise is hierarchical, calibrated from held-out residuals: a per-driver rating error τ drawn once per simulation (correlated across the season — this is what keeps title odds honest instead of inflating leaders to ~100%), an independent per-race σ, and a per-round form random-walk term (mechanism in place; current calibration finds ≈0 residual drift because rolling-form features already absorb car development). σ and τ are calibrated on classified finishers only — DNF chaos enters the simulation exactly once, through explicit DNF injection: a 50/50 blend of the constructor's current-season retirement rate (reliability lives in the car; 2026 reg-change attrition is team-specific) and the driver's 3-season rate scaled by the field's current-vs-trailing attrition ratio. 2026 points rules (sprint weekends included, countback tiebreaks).
  • Driver detail — the exact feature vector behind any prediction.
  • LLM analyst (e key) — a local model explains a prediction using only the feature values it was given; it is instructed not to invent facts.

Methodology

Features are engineered in a single SQL file (shared/features.sql) executed by both the Python training pipeline and the Rust app against the same SQLite database — training/inference feature drift is structurally impossible. The app verifies a SHA-256 contract hash at startup and refuses to run with a stale model.

Feature set (research-backed; see sources in the file header): grid position, qualifying-lap % gap to session best, rolling driver form (last 3 / last 5), constructor rolling form (last 3 events), constructor season share, driver's 4-year history at the circuit, DNF rate (last 10), teammate qualifying delta, championship position.

Training: XGBoost regression on finishing position with rank-weighted samples (podium 3×, points 1.5×) to counter regression-to-the-mean on winners, and monotonic constraints on grid/quali-gap features. Time-based splits: train 2014–2023, validate 2024 (model selection), test 2025+ (reported metrics). Exported to ONNX with a parity gate (ONNX vs XGBoost must agree to 1e-4 and produce identical orderings); inference in Rust via ort.

At deployment the race model's order is a rank blend, 75% model / 25% grid: a 2026 r1–6 backtest showed the raw model tying the grid baseline on order while losing winner/podium hits, and w=0.25 was the only blend weight that helped on both the 2024 validation season and the 2025–26 test seasons. FP2 long-run pace (via FastF1, 2021–26) was evaluated and rejected the same way: weak alone (ρ≈0.33) and harmful to winner/top-3 hits once trained in — constructor season share and quali gap already carry that signal.

Current held-out test metrics live in model/metrics.json and on the TUI's model screen, always next to the honest baseline (predict-the-grid-order), which any model must beat to earn its keep. Metrics are reported twice: over the full classification and over classified finishers only — the second isolates pace-ranking skill from DNF/DSQ chaos (2026's reg-change attrition runs ~2× the 2024–25 rate; 2025's worst-predicted races were post-race disqualifications and mass-attrition outliers, which no grid/form feature can see coming).

Repo layout

shared/   schema.sql + features.sql — single source of truth for data + features
model/    *.onnx + *.features.json + metrics.json (committed; retrain optional)
data/     f1.db SQLite cache (gitignored; built by `make data`)
ml/       Python training pipeline (uv, Python 3.12)
app/      Rust TUI, crate `f1tui`
docs/     ARCHITECTURE.md — module map, ml↔app contract, where to add things

Contributing or pointing an AI agent at this repo? Start with docs/ARCHITECTURE.md — it explains the cross-language contract and the invariants the golden test enforces.

Commands

command what
make run launch the TUI
make data download / refresh historical data
make train full retrain (features → train → evaluate → ONNX export)
make test golden-race parity test (Rust must match Python exactly)
cargo run --release -- predict 2025 10 one-off CLI prediction
cargo run --release -- season championship forecast in the terminal

Keys

↑↓/jk navigate · ENTER predict / driver detail · e LLM explanation · TAB races/season · i model info · r resync · ESC back · q quit

Requirements

macOS or Linux, ~2 GB disk (Rust toolchain + deps), terminal with truecolor. Windows: untested, but nothing is platform-specific beyond the setup script.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages