Skip to content

levers: why the multi-product Q' blend raises NSE (ambiguity decomposition) - #53

Merged
taddyb merged 1 commit into
dam-release-v2from
blend-mechanism
Oct 1, 2026
Merged

taddyb merged 1 commit into
dam-release-v2from
blend-mechanism

Conversation

@taddyb

@taddyb taddyb commented Oct 1, 2026

Copy link
Copy Markdown
Owner

Summary

Explains why the offline multi-product Q' blend (UH 0.50, DIST 0.25, daily LSTM 0.25; experiments/levers/report.txt §2b) lifts the 2,365-gauge population median NSE by +0.026. Analysis only: no src/ changes.

  • experiments/levers/blend_mechanism.py decomposes the routed output blend exactly, per gauge: blend NSE = weighted mean of member NSEs + member spread / var(obs). This is the Krogh & Vedelsby (1995) ambiguity decomposition divided by the observed variance; the script asserts the identity to 1e-8 at every gauge.
  • experiments/levers/blend_mechanism.txt: results on test years (WY1996-2010) and training years (WY1986-1995, zero-step replays).
  • experiments/levers/page/runoff_blend_explainer.html: source of the explainer artifact.
Test years, medians over 2,365 gauges equal weights training-year weights
member NSE UH / DIST / LSTM 0.7391 / 0.7300 / 0.6359 same
weighted mean of member NSEs 0.6957 0.7064
spread (member disagreement) +0.0590 +0.0511
blend 0.7637 0.7650
spread by time scale: year-to-year volume / seasonal / event (< 30 d) 0.06 / 0.16 / 0.76 same

The products mostly miss different storms, and averaging cancels those misses. The LSTM's residuals correlate 0.62 with UH's; the two UH seeds correlate 0.997, which is why averaging seeds gains only +0.001. Most of the gain is present on the training years too (+0.018 vs +0.026), so it is not mainly test-period volume drifts cancelling; that drift is 6 % of the disagreement.

Scope

This is a standard multi-model ensemble gain. It serves the +0.03 population-median skill target and is not a paper result: the offline blend has no single parameter field, and the decomposition is textbook. The engine version (one head trained on blended Q', branch multi-product-forcing) is separate work and is unmeasured.

Stacked on #52 (base dam-release-v2, where experiments/levers/ lives); retarget to master once #52 merges.

Test plan

  • blend_mechanism.py runs on the main workspace's runs and its per-gauge identity assertion passes
  • No src/, config or test changes; three new files only
  • CI

🤖 Generated with Claude Code

https://claude.ai/code/session_015TepsZAS2LkFC5EmvuZrz9

…ition)

blend_mechanism.py decomposes the offline three-product output blend (UH 0.50, DIST 0.25, daily LSTM 0.25)
exactly per gauge: blend NSE = weighted mean of member NSEs + member spread / var(obs) (Krogh & Vedelsby 1995,
divided by the observed variance). Test years WY1996-2010: weighted mean 0.7064 + spread 0.0511, blend 0.7650;
76 % of the spread is event scale (< 30 d), 16 % seasonal, 6 % year-to-year volume. Training years WY1986-1995
show most of the gain too (+0.018 vs +0.026). A standard multi-model ensemble gain serving the +0.03 skill
target; not a paper result. Also the explainer page source (artifact VkdLRvzZVhv2C9bQn8JdEY).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015TepsZAS2LkFC5EmvuZrz9
@taddyb
taddyb merged commit 857ef4f into dam-release-v2 Oct 1, 2026
2 checks passed
@taddyb
taddyb deleted the blend-mechanism branch October 1, 2026 02:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant