Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

An out-of-period test, under a protocol fixed before the run

Chapter 6’s test is not blind (next section). This chapter runs the test that is left: the same members’ future winters under SSP3-7.0, a period no choice in this cookbook was made on, under a protocol fixed before the scored run (self-attested; no external timestamp).

Overview

  1. Why chapter 6’s test is not blind.

  2. The protocol and its decision rule.

  3. Future-period transforms, from the training members only.

  4. The frozen models.

  5. The single scored run, and its reading against the rule.

  6. The limits.

show() prints the source of a lensml.py helper where the chapter uses it.

Prerequisites

ConceptsImportanceNotes
Chapter 6Necessarythe final model, the test and its caveats
Chapter 2Helpfulthe forced response, the wet threshold, the decile bins
Distribution shiftHelpfula model scored on data from another regime than it was fit on
  • Time to learn: about 15 minutes; every cell runs in under a minute from the committed caches.

  • System requirements: the environment.yml at the repository root; no account, no local data beyond the committed caches.

Imports

Why chapter 6’s test is not blind

The 20 test members were scored during development (2026-10-20; the neural network also on 2026-10-29) with the Niño-sign rule, with logistic at the base-rate threshold, which showed no detectable edge, with boosting, the result chapter 6 prints, and in the companion course with a small neural network. Boosting was registered as the final model on 2026-10-29, after those scores had been seen. Every member has been used, so what is left untouched is their future winters: the ssp370 stores, 2016–2100.

The protocol, fixed before the scored run

The protocol was written on 2026-10-29, before any SSP3-7.0 data were read, and is followed without change (self-attested; no external timestamp). It ships verbatim as data/ssp370-test-protocol.md; the hash cell below says whether the file still matches its hash as committed with the test (851d900; the hash itself was recorded on 2026-10-30). Its decision rule, in its own words:

Primary outcome (decided now): precision − base rate for boosting@base-rate on the test members’ future winters, with the same resampling-over-test-members 95% interval as chapter 6. “Edge replicates” if the interval’s lower bound is above 0; “does not replicate” otherwise. Secondary, reported whatever they show: AP − base rate with interval; recall and wet-call share; false alarms per hit; the same numbers for the comparators; the decile wet rates on the training edges with a chi-square test.

Frozen with it: the model and comparators (always-wet, always-dry, Niño-sign, logistic@base-rate), fitted as in chapter 6 and never refitted. One clarification was made, by the author’s account before the run: “the training edges” are chapter 2’s training-member decile edges (see the sensitivity check below).

Loading...
data/ssp370-test-protocol.md sha256 11d291795a00bb6d10c818c27a40f9a2a45dff1d8641dfacf931a044489d9628 (first 16: 11d291795a00bb6d)
protocol file: matches the hash committed with the test

The future table

data/member_winters_ssp370.csv was derived with chapter 1’s derive_member_winters (same members, boxes and seasons) from the ssp370 stores, winters 2016–2100; the reader asserts its header. The cell prints only counts.

cache header has no AUTUMN_MONTHS field (it predates the field): taken as AUTUMN_MONTHS=[9, 10, 11], the only autumn the derivation code had: the file's autumn is assumed, not read from the header. A rebuild records it.
# derived by lensml.py: experiment=ssp370 SEASON=DJF WINDOW=(2016, 2100) FRONT_RANGE={'lat': slice(38.5, 40.5, None), 'lon': slice(253.75, 256.25, None)} NINO34={'lat': slice(-5, 5, None), 'lon': slice(190, 240, None)} AUTUMN_MONTHS=[9, 10, 11] n_members=100 RNG_SEED=0 access=2026-10-29
test: 20 members · 1700 future winters
train: 80 members · 6800 future winters

Future-period transforms, from the training members only

The forcing differs under SSP3-7.0, so the forced curve and wet threshold are refitted on the training members’ future winters, with chapter 2’s decade check. No test row is read.

future wet threshold (pooled training members) = +0.0883 mm/day; training-member future base rate 0.333
nino34_anom  training members, decade-mean anomaly in standard errors: worst +0.85 (the 2050s) · tolerance ±3 → PASS
prect_anom   training members, decade-mean anomaly in standard errors: worst -1.12 (the 2060s) · tolerance ±3 → PASS
SON Niño 3.4 anomaly SD, training members: historical 1.372 K · future 1.538 K · ratio 1.121

The frozen models

Each model is fitted once on the 80 training members’ historical winters, as in chapter 6 (the final model is the register’s trial 5). Nothing refits.

frozen: boosting@base-rate, always-wet, always-dry, nino-sign, logistic@base-rate

The scored run

This cell is the test: the primary outcome, then the secondary outcomes in the protocol’s order, then the decile chi-square. A counter marks any re-run in the same kernel, and the cell after it compares the result with the first scored run, so a library upgrade that changed it shows as “differs”.

scored run #1
PRIMARY OUTCOME — boosting@base-rate, precision − base rate on the test members' future winters: +0.011, 95% interval over test members [-0.009, +0.031] → DOES NOT REPLICATE (pre-registered rule: replicates only if the lower bound is above 0)

SECONDARY OUTCOMES, in the protocol's order:
20 members · 1700 winters · base rate 0.317
boosting@base-rate: precision − base rate  +0.011   95% interval over members [-0.009, +0.031]  →  NOT distinguishable from no skill
boosting@base-rate: AP − base rate         +0.014   95% interval over members [-0.003, +0.038]  →  NOT distinguishable from no skill
boosting@base-rate: recall 0.570  wet-call share 0.551  false alarms 630 · hits 307 · false alarms per hit 2.05
always-wet: precision − base rate  +0.000   95% interval over members [+0.000, +0.000]  →  NOT distinguishable from no skill
always-wet: AP − base rate         +0.000   95% interval over members [+0.000, +0.000]  →  NOT distinguishable from no skill
always-wet: recall 1.000  wet-call share 1.000  false alarms 1161 · hits 539 · false alarms per hit 2.15
always-dry: precision − base rate  -0.317   95% interval over members [-0.337, -0.295]  →  below no skill
always-dry: AP − base rate         +0.000   95% interval over members [+0.000, +0.000]  →  NOT distinguishable from no skill
always-dry: recall 0.000  wet-call share 0.000  false alarms 0 · hits 0 · false alarms per hit undefined (no hits)
nino-sign: precision − base rate  -0.007   95% interval over members [-0.026, +0.010]  →  NOT distinguishable from no skill
nino-sign: AP − base rate         -0.003   95% interval over members [-0.012, +0.005]  →  NOT distinguishable from no skill
nino-sign: recall 0.484  wet-call share 0.495  false alarms 581 · hits 261 · false alarms per hit 2.23
logistic@base-rate: precision − base rate  +0.006   95% interval over members [-0.011, +0.025]  →  NOT distinguishable from no skill
logistic@base-rate: AP − base rate         -0.010   95% interval over members [-0.025, +0.013]  →  NOT distinguishable from no skill
logistic@base-rate: recall 0.516  wet-call share 0.506  false alarms 583 · hits 278 · false alarms per hit 2.10
wet rate by bin of the autumn Niño 3.4 anomaly (edges given):
                     wet_rate    n  binomial_se  (rate - base) / se
nino34_anom bin (K)                                                
(-inf, -1.774]          0.252  230        0.029              -2.266
(-1.774, -1.137]        0.372  172        0.037               1.493
(-1.137, -0.726]        0.354  147        0.039               0.930
(-0.726, -0.366]        0.350  157        0.038               0.874
(-0.366, -0.00268]      0.322  152        0.038               0.140
(-0.00268, 0.364]       0.285  151        0.037              -0.879
(0.364, 0.738]          0.326  141        0.039               0.233
(0.738, 1.167]          0.339  165        0.037               0.606
(1.167, 1.743]          0.291  165        0.035              -0.740
(1.743, inf]            0.309  220        0.031              -0.256
chi-square test of wet against bin: chi2 = 10.4, dof = 9, p = 0.32

scored result: matches the first scored run
chapter 6's estimate (historical test members) +0.018; inside this interval [-0.009, +0.031]: True
outside the protocol: with this interval's width (SE ≈ 0.0102), a true edge of chapter 6's size clears a lower bound of 0 about 42% of the time
Horizontal interval plot: for each frozen model — boosting at the base-rate threshold, always-wet, the Niño-sign rule and logistic at the base-rate threshold — a dot for precision minus the base rate on the test members' SSP3-7.0 winters and a gold bar for its 95% interval over test members, against a dashed line at zero, no skill. Always-dry is not drawn: it calls nothing wet, so its precision is undefined.

Reading the run against the rule

The edge does not replicate under the rule fixed, by the author’s account, before the run. On the PRIMARY OUTCOME line, the final model’s precision interval includes zero. The chapter 6's estimate line shows it also includes chapter 6’s estimate, so this test cannot separate no edge from an edge of that size; the outside the protocol line shows how small the test was. It gives no support for a briefing calling the winter statistically wetter.

The secondary outcomes agree: the final model’s AP − base rate line is not distinguishable from no skill, no comparator clears the base rate on precision, and every model that calls wet makes more false alarms than hits (the false alarms per hit values). Always-dry calls nothing wet, so its precision is undefined: the scored-run line reads “below no skill” only because precision is scored 0 when nothing is called wet (it is not drawn in the figure). The decile chi-square line does not reject chance.

This does not show the historical edge was an artefact (a shift could hide a real but fragile relation, limit 1), but the chapter 6 edge is not evidence a forecaster could lean on.

A choice the protocol left open: the bin edges

The protocol did not say which period’s “training edges”; the run used chapter 2’s historical ones (the clarification above, by the author’s account made before the run). The cell below tries the future-winter edges, outside the protocol: the two p values differ and neither rejects chance at 0.05.

chapter 2's historical training edges (the run): chi2 10.4, dof 9, p 0.32
the training members' future-winter edges: chi2 11.9, dof 9, p 0.22

Limits

  1. A different period under stronger forcing. A failure can be shift as well as no skill: the model was fit on 1900–2014 and scored on 2016–2100, and the input is wider (the SON Niño 3.4 anomaly SD line). Rodgers et al. (2021) find “a decrease in ENSO amplitude” in the Niño 3.4 region and “decreased precipitation co-variance with ENSO” over the Pacific Northwest and much of the southern US and Mexico under the same forcing; this SON box mean moves the other way (the SD line prints a wider input), though they compare DJF 1960–1989 with 2070–2099 while this pools 2016–2100 against 1900–2014; the two are not reconciled here. Either way, this test asks whether the edge holds under a changed relation as much as whether it was real.

  2. A model world. CESM2 scored against CESM2; nothing here touches observations.

  3. The same members. The 20 test members were scored during development; their future winters are new data, and the target shows little year-to-year memory (chapter 3’s lag-1 line); what carries over is that these members took part in choosing the model.

  4. The existing limits. Chapter 6’s limits 2–7 hold unchanged.

Summary

A protocol fixed the model, outcomes and decision rule before any SSP3-7.0 data were read (self-attested); the frozen models were scored once. The edge does not replicate under the rule fixed before the run (the PRIMARY OUTCOME line), and the interval also includes chapter 6’s estimate.

What’s next?

The same protocol could be run in another season (FMA), another box or another ensemble, each written down before its data are read. Observed winters remain the test that would tell a model result from a real one.

Resources and references

ResourceWhere it bearsLicence
Grover, M., & Banihirwe, A. (2021). NCAR CESM2 Large Ensemble Cloud-Optimized Dataset. NSF NCAR CISL. doi:10.26024/y48t-q717the ssp370 stores (required citation)UCAR Data Terms of Use
Rodgers, K. B. et al. (2021). Earth System Dynamics 12, 1393–1411. doi:10.5194/esd-12-1393-2021the ensemble and its SSP3-7.0 forcing (required citation); limit 1CC BY 4.0
scikit-learn User Guide, §12 Common pitfalls. https://scikit-learn.org/stable/common_pitfalls.htmltransforms fit on training data onlyBSD-3-Clause

Results based on the CESM2 Large Ensemble acknowledge the CESM2 Large Ensemble Community Project and supercomputing resources provided by the IBS Center for Climate Physics in South Korea.