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.

A refinement is a trial: one change, scored against the incumbent on the same folds, and promoted only if the gain beats the run-to-run spread. This chapter keeps the register of every trial, and says which were chosen after their scores had been seen.

Overview

  1. The corrected paired t-test, written out.

  2. The promotion rule, the Bonferroni line and the trial budget.

  3. The register: three rungs, then two threshold trials chosen after the fact.

  4. One paired test by hand.

Shared code lives in lensml.py; show() prints a function’s source. Terms are in the glossary.

Prerequisites

ConceptsImportanceNotes
Chapter 4Helpfulthe ladder and the threshold table
A paired t-testHelpfula mean difference over its standard error
scikit-learn: statistical comparison of modelsHelpfulthe source of the test
  • Time to learn: about 15 minutes; the trials take under a minute.

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

Imports

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.
train: 80 members / 9200 winters   test: 20 members / 2300 winters   N_FOLDS = 5

The test

Unidata’s instruction is to run trials “until you are satisfied with the evaluation metrics, or they no longer improve with new trials”. Each trial repeats the member-grouped folds N_REPEATS times on the same draws for both models, so every fold gives one paired difference. The test is the Nadeau–Bengio corrected paired t-test, written out below from scikit-learn’s example Statistical comparison of models using grid search (BSD-3-Clause). It is one-sided: a candidate must beat the incumbent, so a loss prints p near 1.

The rule, the Bonferroni line, the budget

Recall alone rewards calling wet always; precision alone, almost never. So a candidate is promoted only if one of the two improves measurably — p < 0.05 with a positive gap — while the other does not fall on average (mean gap ≥ 0). Each register row carries both tests and the wet-call share (called_wet_cand, called_wet_inc).

The example warns that “[I]f multiple models are statistically compared, a multiple comparisons correction is needed when using the frequentist approach”. Each p here is uncorrected, so the register bounds the looks at MAX_TESTED_TRIALS rows, two metrics each, and prints the Bonferroni line (0.05 ÷ the looks so far). A p between that line and 0.05 is a promotion under the uncorrected rule only. The line counts only this register’s looks.

Loading...

The ladder climb

The three rungs, each against the incumbent, fixed in chapter 4 (chapter 3 had already scored one of them at the default threshold).

first incumbent: nino-sign   fold draws per trial: 10 × 5 folds = 50 paired scores per metric
incumbent after the ladder (3 trials): nino-sign
Bonferroni line after 3 tested row(s) = 6 looks: p < 0.0083   (at the cap of 6 rows: p < 0.0042). A row promoted on a p above this line is promoted under the uncorrected rule only.
Loading...

Two threshold trials, chosen after the fact

At the default 0.5 the probabilistic rungs almost never call wet, so the next two trials lower the threshold to the base rate. Neither was blind: logistic at the base rate is in chapter 4’s threshold table, and boosting at the base rate is chapter 3’s contrast model, registered because its score there had been seen. The Bonferroni line does not count those looks, so their p is optimistic. Trial 4’s promotion is over the sign rule, whose precision is below the always-wet bar (chapter 4), and its p is above the Bonferroni line: read it as a promotion over a rule with no skill, not as skill. Chapters 6 and 7 are the remaining checks; chapter 6’s test members were scored during development, so it is provisional.

Loading...
incumbent after 4 trials: logistic@base-rate
Bonferroni line after 4 tested row(s) = 8 looks: p < 0.0063   (at the cap of 6 rows: p < 0.0042). A row promoted on a p above this line is promoted under the uncorrected rule only.
Loading...
incumbent after 5 trials: boosting@base-rate
Bonferroni line after 5 tested row(s) = 10 looks: p < 0.0050   (at the cap of 6 rows: p < 0.0042). A row promoted on a p above this line is promoted under the uncorrected rule only.
boosting@base-rate vs logistic@base-rate: wet-call share 0.599 vs 0.481 (change +0.118); recall 0.634 vs 0.487 (gain +0.147)
calling wet more often, with no skill, accounts for +0.118 of the +0.147 recall gain (80%); the rest, +0.030, is the ranking
Loading...

With no skill, recall equals the wet-call share, so the accounts for line splits the recall gain into share and ranking. Precision is the half that speaks to skill.

Your trial

One tested row is left in the budget. Write it down before you score it: one change, why, and which metric should move (a tree threshold or depth, a leaf size, the boosting learning rate). Add it to YOUR_TRIALS, run the cell, read the row against the spread and the Bonferroni line, then copy YOUR_TRIALS into chapter 6, which rebuilds this register.

incumbent after 5 trials: boosting@base-rate   (tested rows left: 1)
Bonferroni line after 5 tested row(s) = 10 looks: p < 0.0050   (at the cap of 6 rows: p < 0.0042). A row promoted on a p above this line is promoted under the uncorrected rule only.
Loading...

One paired test, by hand

The cell below redoes the test as arithmetic on one register pair (by default the last promotion, on its metric): per-fold differences, corrected standard error, t, and the one-sided p from scipy. A loss prints p near 1, so it also reads the left tail. Change PAIR_A, PAIR_B or HAND_METRIC, and say whether the lead is a measured difference.

default pair: register row 5 (boosting@base-rate vs logistic@base-rate, verdict 'promoted: recall up, no precision loss') → metric recall
boosting@base-rate − logistic@base-rate on recall: 50 paired fold scores   n_train = 7360   n_test = 1840
means 0.634 vs 0.487   gap +0.1472   per-fold SD of the gap 0.0609   corrected standard error 0.0316  (the spread the test uses)
t = 4.65   p = 1.25e-05   →  p < 0.05: a measured GAIN for boosting@base-rate under the uncorrected rule; read it against the Bonferroni line below
Bonferroni line after 5 tested row(s) = 10 looks: p < 0.0050   (at the cap of 6 rows: p < 0.0042). A row promoted on a p above this line is promoted under the uncorrected rule only.

Summary

Every refinement is a recorded trial with a one-sided, fold-corrected paired test. Promotion needs a measured gain on one decision metric and no average loss on the other, read beside the Bonferroni line. The two threshold trials were chosen after their scores were seen, so their promotions are leads to test, not findings. The last promotion is the model chapter 6 tests.

What’s next?

Chapter 6 runs the held-out test once on the final incumbent.

Resources and references

ResourceWhere it bearsLicence
scikit-learn example, Statistical comparison of models using grid search. https://scikit-learn.org/stable/auto_examples/model_selection/plot_grid_search_stats.htmlthe corrected paired t-test; the multiple-comparisons warningBSD-3-Clause
NSF Unidata, Supervised Machine Learning Readiness. https://github.com/Unidata/supervised-ml-readinessrefine until trials no longer improveApache-2.0