Scientific computing demonstration
Synthetic Streamflow Forecasting Benchmark
A fair river flow benchmark on synthetic data.
- Role
- Project author
- Classification
- Synthetic demonstration
Problem
Two models were ranked on different targets.
How it was solved
Every method now faces the same days and the same baseline.
- Same days
- Persistence
- Models
Result
0.994
ridge, the only method to beat persistence
- XGBoost0.985
- Persistence0.988
- Ridge0.994
Built with
- XGBoost
- statsmodels
- scikit-learn
Scientific computing / Benchmark
A leaderboard invites one reading: rank the rows. These three were not scored on the same task, and the gap between the questions is wider than the gap between the models.
Persistence baselineR2 0.988
A leaderboard whose rows were asked different questions
This diagram in words
- Synthetic series source — Fifteen years from a seed. Not a measured river.NumPy
- Chronological holdout gate — Split by date, and it decides what each row is told.
- Five-seed repeat process — The same fit five times, so one seed cannot be the result.XGBoost
- Daily baselines process — Persistence and seasonal naive, given the same information.statsmodels
- Same task? gate — One step ahead with yesterday's value supplied is a different question.
- Error analysis artifact — Where the gap between the questions exceeds the gap between the models.Matplotlib
Read the full background
Problem
Why this work exists
An earlier version of this repository ranked XGBoost at R2 0.979 above SARIMAX at 0.721. The two numbers were scored on different targets, daily and monthly, and the only baseline offered was a day-of-year mean that could not win. The question became which methods beat a fair baseline on the same rows.
Contribution
What I can claim
Rebuilt the comparison so every daily method is scored on the same 730 held-out days, added persistence, random walk with drift and a trend-corrected day-of-year baseline, added a ridge model on the same features, and repeated the whole comparison over five seeds.
Method
Three numbers that are not the same measurement
A benchmark table invites one reading: rank the rows.
R2 0.9848one step ahead, given yesterday’s measurement — lag 1 and lag 2 carry 94.4% of the model
Rank
Read as a leaderboard, gradient boosting beats classical statistics by a wide margin and the naive baseline is not close.
Open
One row predicts tomorrow having been given today's measurement.
Attribute
The two most recent lag features carry most of the strongest model, on a series whose day-to-day autocorrelation is very close to one - because the series was generated by a recursion that is public.
What this does not show
This benchmark is deterministic and synthetic, and its evaluation is one step ahead with observed discharge supplied as an input. It exercises an evaluation pipeline honestly; it is not a claim about any particular river.
How it was built
System
Workflow and decisions
- 1Synthetic 15-year series
- 2Chronological holdout
- 3Fair daily baselines
- 4Five-seed repeat
- 5Error analysis
- XGBoost
- statsmodels
- scikit-learn
- pandas
- NumPy
- Matplotlib
Evidence
What is actually versioned
Predicting yesterday's value, on the same 730 held-out days as every daily model.
Twenty engineered lag, rolling and calendar features, and still below persistence; it fails to beat it on all five seeds.
The only method that improves on persistence, and it does so on all five seeds.
How the work is checked
Quality controls
How the work is checked
- Fixed-seed data generator and chronological test split
- Every daily method scored on the same held-out rows
- Comparison repeated over five seeds and recorded in results/benchmark.json
- SARIMAX reported on monthly means and kept out of the daily ranking
Limitations
Where the evidence stops
- Synthetic data cannot establish real-catchment performance
- The feature models see same-day observed weather, so they are nowcasts rather than pure one-step-ahead forecasts
- The benchmark does not test recursive multi-day behaviour or distribution shift
What this changed in my practice
What this changed in my practice
A leaderboard is only as good as its weakest baseline. On a series this persistent, repeating yesterday's value is the number every model has to beat.