MZQMohd Zamin Quadri
All work

Forecasting

A Published Margin That Does Not Survive an Ordinary Year

Forecasting Munich's road accidents.

Role
Project author
Classification
Reproducible experiment
Inspect repository
Two runs of one protocol on one axis through zero. The published margin stays clear of it; the ordinary-years margin crosses it, and crossing it is the finding.One axis of improvement over a seasonal naive baseline, with zero drawn as a full-height line because which side of it a result lands on is the whole question. The published window, 2021 and 2022, sits at a margin of 0.2344 and its three-month moving-block bootstrap interval opens from 0.072 to 0.333, entirely clear of zero. The identical protocol run over 2018 and 2019 then arrives beneath it at a margin of minus 0.1553, and its interval opens from minus 0.368 to 0.069 - across zero, which is circled. An interval spanning zero has not established its own sign, so the published margin does not survive the move to ordinary years. How many of the seven series each window won follows, seven of seven against three of seven. The sequence notes that both intervals are the moving-block ones from ten thousand draws rather than the narrower independent pair, because monthly accident counts carry memory and the narrower interval would have flattered the published result, and closes on the data underneath: 1,932 monthly observations and 24 months held out.
  1. Problem

    The baseline was forecasting a pandemic year.

  2. How it was solved

    I reran the same test on ordinary years.

    1. Published window
    2. Ordinary years
    3. Compare
  3. Result

    +23.4% → −15.5%

    the model's margin in ordinary years

    • Published window+23.4%
    • Ordinary years−15.5%
  4. Built with

    • scikit-learn
    • pandas
    • FastAPI
    • pytest
    See the evidence on GitHub
One axis of improvement over a seasonal naive baseline, with zero drawn as a full-height line because which side of it a result lands on is the whole question. The published window, 2021 and 2022, sits at a margin of 0.2344 and its three-month moving-block bootstrap interval opens from 0.072 to 0.333, entirely clear of zero. The identical protocol run over 2018 and 2019 then arrives beneath it at a margin of minus 0.1553, and its interval opens from minus 0.368 to 0.069 - across zero, which is circled. An interval spanning zero has not established its own sign, so the published margin does not survive the move to ordinary years. How many of the seven series each window won follows, seven of seven against three of seven. The sequence notes that both intervals are the moving-block ones from ten thousand draws rather than the narrower independent pair, because monthly accident counts carry memory and the narrower interval would have flattered the published result, and closes on the data underneath: 1,932 monthly observations and 24 months held out.

Reproducible experiment / Forecasting

The model beats its baseline by 23.4 per cent. Run the same protocol three years earlier and the sign flips, because the baseline on the published window repeats a pandemic.

The published margin+23.4%

The same protocol, run on two windows

same protocolthe window was the resultSeven published seriesCity open data, one modelfitted per series.Trend window chosenSelected on two validationyears, before anything is…Refit and score onceOn the two years after theones that chose the window.Published windowThe window the original 23.4%margin was measured on.Pre-pandemic windowThe identical protocol, threeyears earlier.Bootstrap both marginsOver held-out months, andapplied to both runs rather…Both margins at zeroOne stays clear of zero. Theother crosses it, and that is…
The fork is the experiment. Running one protocol on the published window and on a pre-pandemic window produces margins that disagree about their sign, and the bootstrap is applied to both rather than to either alone.

This diagram in words

  1. Seven published series source — City open data, one model fitted per series.
    pandas
  2. Trend window chosen gate — Selected on two validation years, before anything is scored.
  3. Refit and score once process — On the two years after the ones that chose the window.
    scikit-learn
  4. Published window process — The window the original 23.4% margin was measured on.
  5. Pre-pandemic window process — The identical protocol, three years earlier.
  6. Bootstrap both margins gate — Over held-out months, and applied to both runs rather than one.
    pytest
  7. Both margins at zero artifact — One stays clear of zero. The other crosses it, and that is the finding.

01 / 723.4% better than seasonal naiveOn 2021 to 2022, the window the project published.

Test window
2021 to 2022
Scaled MAE
0.1531 against 0.1999 naive
Margin
23.4%
Moving-block interval
0.072 to 0.333
Draws
10,000, 3-month blocks
One axis of improvement over a seasonal naive baseline, with zero drawn as a full-height line because which side of it a result lands on is the whole question. The published window, 2021 and 2022, sits at a margin of 0.2344 and its three-month moving-block bootstrap interval opens from 0.072 to 0.333, entirely clear of zero. The identical protocol run over 2018 and 2019 then arrives beneath it at a margin of minus 0.1553, and its interval opens from minus 0.368 to 0.069 - across zero, which is circled. An interval spanning zero has not established its own sign, so the published margin does not survive the move to ordinary years. How many of the seven series each window won follows, seven of seven against three of seven. The sequence notes that both intervals are the moving-block ones from ten thousand draws rather than the narrower independent pair, because monthly accident counts carry memory and the narrower interval would have flattered the published result, and closes on the data underneath: 1,932 monthly observations and 24 months held out.
Read the full background

Problem

Why this work exists

The model beats a seasonal-naive baseline by 23.4% on the published window, on all seven series. That baseline repeats the previous calendar month, and on this window the previous year is 2020, so the baseline forecasts a pandemic. Saying so in a caveat is not the same as measuring it.

Contribution

What I can claim

Ran the identical protocol three years earlier, over a stretch where nothing unusual happened, with the same code, the same metrics and the same number of held-out rows. Then measured both margins against resampling, because a single number on 24 months says nothing about whether it would hold on a different 24 months.

Method

The same protocol, asked twice

A forecasting model beats its baseline on a published series, and the margin looks worth reporting.

  1. Model

    One model per published series, each fitted on its own history.

  2. Select

    The trend window is chosen on validation years and then left alone.

  3. Score

    Refit once and score once on the years that follow.

  4. Repeat

    The identical protocol is then re-run on an earlier, ordinary window.

  5. Bound

    Both margins are bootstrapped over held-out months, and neither is comfortably away from zero.

  6. What this does not show

    Both margins rest on twenty-four months across seven series. Neither should be read as settled, and the pre-pandemic one explicitly cannot be distinguished from zero. The series are published counts of recorded accidents, which is not the same as accidents.

How it was built

System

Workflow and decisions

One protocol, parameterised by which years are validation, which year training ends on, and which two years are held out. The published run and the pre-pandemic run are two calls to it, which is what makes them comparable at all.

  1. 1Seven published series, one model each
  2. 2Select the trend window on two validation years
  3. 3Refit and score once on the two years after
  4. 4Re-run the whole protocol on a pre-pandemic window
  5. 5Bootstrap both margins over held-out months
  • scikit-learn
  • pandas
  • FastAPI
  • pytest
  • GitHub Actions

Evidence

What is actually versioned

The published margin+23.4%

Scaled MAE 0.1531 against a seasonal-naive 0.1999 on 168 held-out monthly observations, winning on 7 of 7 series. A 3-month moving-block bootstrap puts it between 7.2 and 33.3 per cent, which stays clear of zero.

The same protocol, ordinary years-15.5%

Selected on 2016 and 2017, scored once on 2018 to 2019. The sign flips and the model wins on 3 of 7 series. Its interval runs -36.8 to 6.9 per cent, so on 24 months this margin cannot be told apart from no difference either way.

What the move costs1.66x the margin

Moving to an ordinary period costs more than the entire published margin, which is what the repository records rather than what it claims for the method.

The data1,932 monthly observations

7 series, 2000 to 2022, from the Landeshauptstadt Muenchen, open data portal. Errors are scaled by each series' own level before averaging, because the largest series is about 169 times the smallest.

How the work is checked

Quality controls

How the work is checked

  • Both windows are produced by the same function, so the two rows are not two scripts that happen to agree
  • The held-out years are scored once; the trend window is chosen on separate validation years
  • The bootstrap is paired, so every method is scored on the same resampled months and what varies is the margin rather than the noise in each
  • It is run twice, independently and in blocks of three months, and the wider interval is the one the README tells you to believe
  • Errors are scaled per series before averaging, so the small series are not drowned out by the large ones

Limitations

Where the evidence stops

  • Both margins rest on 24 months of seven series. Neither row should be read as settled, and the pre-pandemic one explicitly cannot be distinguished from zero
  • The two windows also select different models: a 12-year trend window against a 6-year one. Same procedure, different data, so the comparison is between two protocol runs rather than one model on two periods
  • Counts only. No exposure denominator, no severity weighting, and no causal claim about why any series moves
  • A coding-challenge project rebuilt afterwards, not a deployed forecasting service
What this changed in my practice

What this changed in my practice

A baseline carries its own history, and on this window the history was a pandemic. The honest way to find that out was not to add a sentence of caveat but to run the whole protocol somewhere the pandemic was not, and then to check whether either answer survives being resampled. Only one of them does.

Next evidence milestone: More held-out periods. Two windows give two answers and no sense of the spread between them; running the same protocol across every available pair of years would say whether the published window is unusual or whether the margin is simply noisy from one period to the next.