ML model trained on ~10 years of F1 data (via FastF1) to predict the 2026 constructor championship standings. Emphasizes early-season performance signals — auto-widened to cover however much of the season has actually run — and a rule-change-year adaptation variable to capture how teams historically perform during major regulation shifts like 2026.
A rebuild is underway that replaces the season-level regression below with a per-driver, per-race hierarchical Bayesian pace model, simulated forward to produce next-race, drivers'-championship, and constructors'-championship forecasts from one engine instead of three separate questions. Full design in docs/grid-prophet-v2-spec.md.
Status: Phase 0 (data layer) complete. src/collect_v2.py builds data/driver_rounds.csv — one row per driver per session (qualifying/sprint/race) per round, 2018–2026, including a clean-air lap filter, per-round weather, and DNF-cause categorization. Run it with:
PYTHONPATH=src python -m collect_v2 --start-year 2018 --end-year 2026 # resumable; re-run to pick up new rounds
PYTHONPATH=src python -m build_driver_meta # derives data/driver_meta.csv (debut season per driver)
PYTHONPATH=src python -m validate_driver_rounds # writes data/driver_rounds_validation.mdSupporting reference tables (data/circuits.csv, data/dnf_status_map.csv) are hand-maintained and tracked in git; everything else FastF1-derived (driver_rounds.csv, driver_meta.csv, the FastF1 disk cache) is local and reproducible, same as the v1 outputs below.
One validated finding worth knowing before building on this data: race clean-air pace correlates with qualifying gap at ~0.6 Spearman (median-lap version; a single-fastest-lap version was tried and performs worse, ~0.5) — below the spec's original ~0.8 assumption. Investigated and confirmed genuine (not a filter bug or bad data) — see the spec's §3.1 empirical note. The v2 model is designed to tolerate this (quali and race pace share latent car/driver terms but keep separate noise terms), so it's a documented characteristic of the signal, not an open blocker.
The v1 pipeline below keeps running as-is — it's the benchmark v2 has to beat, per the spec's phase-3 exit criteria, not something being replaced yet.
Using Claude Code? Clone the repo and run /pit-wall — it installs dependencies and runs the full pipeline for you. Pass args to run a specific stage, e.g. /pit-wall predict --ensemble or /pit-wall update. See .claude/skills/pit-wall/SKILL.md.
Otherwise, run it manually:
pip install -r requirements.txt
# Run the full pipeline in one command
PYTHONPATH=src python -m src run
# Or step by step
PYTHONPATH=src python -m src collect # Pull historical data from FastF1
PYTHONPATH=src python -m src features # Build feature matrix
PYTHONPATH=src python -m src train # Train model + cross-validate
PYTHONPATH=src python -m src predict # Generate 2026 predictions (with bootstrap CI)
PYTHONPATH=src python -m src plots # Generate visualisation charts
# Or via Makefile
make run
make plots| Rank | Constructor | Predicted Share | 80% CI |
|---|---|---|---|
| 1 | Mercedes | 26.2% | ± 2.3% |
| 2 | Ferrari | 23.6% | ± 1.2% |
| 3 | McLaren | 15.0% | ± 1.2% |
| 4 | Red Bull Racing | 15.0% | ± 1.1% |
| 5 | Alpine | 4.9% | ± 0.5% |
| 6 | Racing Bulls | 4.7% | ± 0.5% |
| 7 | Haas F1 Team | 1.7% | ± 0.3% |
| 8 | Audi | 1.5% | ± 0.3% |
| 9 | Williams | 1.4% | ± 0.3% |
| 10 | Cadillac | 0.2% | ± 0.2% |
| 11 | Aston Martin | 0.1% | ± 0.1% |
PYTHONPATH=src python -m src <command> [flags]| Command | Description |
|---|---|
collect |
Pull historical race results from FastF1 |
features |
Build per-constructor, per-season feature matrix |
train |
Train + cross-validate model; optionally build ensemble |
predict |
Generate 2026 predictions with bootstrap confidence intervals |
run |
Run full pipeline: collect → features → train → predict |
update |
Auto-detect latest completed round and re-predict |
plots |
Generate all four visualisation charts |
# predict.py
--rounds N # Ad-hoc override: use N rounds of early-season data (default: EARLY_ROUNDS=2)
--ensemble # Use the ensemble model instead of base model
--no-ci # Skip bootstrap confidence intervals (faster)
# features.py
--early-rounds N # Override the early-season round window (default: EARLY_ROUNDS=2)
# train.py
--ensemble # Build ensemble bundle after training base model
--ensemble-out # Path for ensemble pkl (default: models/Grid_Prophet_ensemble.pkl)make update
# or
PYTHONPATH=src python -m src updateAuto-detects the latest completed 2026 round from FastF1, rebuilds features.csv using that many rounds as the early-season window for both historical training seasons and the live 2026 row (so training and prediction never see a mismatched window), retrains the model, and re-predicts. Saves a round-stamped snapshot (data/predictions_2026_r{N}.csv) alongside the current predictions_2026.csv. run does the same after a fresh collect.
The model uses per-constructor, per-season features — including early-season dominance signals (points share, average finish, DNF rate, grid-to-finish delta, teammate head-to-head, in-window development trend), historical rule-change adaptation scores, prior-year momentum, and driver quality proxies — to predict each team's share of total championship points. Rule-change years are weighted more heavily during training to better capture the dynamics of regulation shifts. Before comparing Ridge and XGBoost, train.py runs LassoCV feature selection to drop features that don't earn their keep against the ~120-row dataset.
An optional ensemble model blends the full-data model with a rule-change-years-only sub-model (trained on 2014, 2015, 2022, 2023). The blend weight α is tuned via leave-one-season-out CV on rule-change seasons.
Bootstrap confidence intervals (N=500) are computed after prediction and shown in the terminal table alongside each constructor's predicted share.
| File | Description |
|---|---|
data/race_results.csv |
Raw race results 2014–2026 |
data/constructor_standings.csv |
Historical championship standings |
data/features.csv |
Per-constructor, per-season feature matrix |
data/cv_results.csv |
Leave-one-season-out CV results |
data/predictions_2026.csv |
2026 predictions with CI columns |
models/Grid_Prophet_model.pkl |
Trained base model bundle |
models/Grid_Prophet_ensemble.pkl |
Ensemble model bundle (if built) |
plots/cv_accuracy.png |
Predicted vs actual rank per CV season |
plots/spearman_by_season.png |
Spearman ρ by season, RC years highlighted |
plots/predictions_2026.png |
2026 standings chart with 80% CI error bars |
plots/feature_importance.png |
Feature importances / Ridge coefficients |
make collect make features make train make predict
make run make update make plots make clean
make clean removes derived data files and model pkls. Raw collected data (race_results.csv, constructor_standings.csv) is preserved.
See PLANNING.md for the staged implementation plan and PROJECT.md for detailed project context and design decisions.