Read the full writeup →
Majors course difficultyJeremy Lee · 2026

Same runner, two courses: the paired method finds each course's penalty within 8 seconds

To test course-ranking methods against an answer I already knew, I built a simulated elite field for the six World Marathon Majors, 2015 to 2024, and planted a time penalty on each course. The within-runner paired comparison found them best: it read Boston as 101 seconds slower than Berlin against a planted 105, and missed no course by more than 7.3 seconds.

Seconds slower than Berlinbar: paired estimate · tick: planted
  1. 1Boston +101.0of 105
  2. 2New York +77.7of 85
  3. 3London +30.7of 35
  4. 4Tokyo +21.0of 28
  5. 5Chicago +11.4of 12
  6. 6Berlin 0anchor
Within-runner paired estimate, weather-normalizedPenalty planted in the simulation

From outputs/analysis_results.csv (estimates) and src/build_data.py (planted penalties). Bootstrap 95% intervals are about ±2 s on every course. The estimate falls short of the planted value on all five courses.

Three methods

A weighted composite (0.15, 0.50, 0.35) gives a Course Difficulty Index with Berlin at 1.000. Boston comes out at 1.0092 and New York at 1.0089: the elevation model's negative Boston number pulls the two almost level.

What this doesn't show

The race results and athletes are simulated, so none of these numbers measures the courses themselves. The test is also easier than race data would be, because the weather correction uses the same curve that generated the times. Whether Boston is 105 s slower than Berlin, or faster as the elevation model says, this data can't tell.