Machine learningLoading progress…

Experiments and reproducibility

Construct a leakage-resistant pipeline and select an evaluation procedure that reflects deployment.

Two runs, two numbers, no idea why

Last week a run scored 78.3%. Today, "the same code" scores 62.9%. Without a record you cannot tell whether the model got worse, the data changed, or you are comparing two different experiments. A result is only a fact about a model together with the exact data, split, preprocessing, settings, library versions and code that produced it.

fieldRun A (last week)Run B (today)
commandpython train.py --split-seed 3python train.py --split-seed 7
split seed37
data filetrain.csvtrain.csv
libraryfitlib 1.4fitlib 2.0
fit_intercept(default)(default)
test accuracy78.3%62.9%
The log shows names, not contents or defaults. Reveal them.
Edit run B

fitlib is a made-up library for this exercise. In it, the default of fit_intercept changed between versions 1.4 and 2.0.

Reveal the hidden fields, then change them one by one. Only some differences are visible in a normal log. (fitlib is a made-up library; in it a default changed between versions.)

What a seed does, and what it does not

A seed fixes randomness: the shuffle in the split, the initial weights. It makes this code on this data repeatable. It does not freeze the data file, the library's defaults, or your preprocessing. Starting from run A and changing a single item to run B's value moves accuracy by 1.7 points for the seed, 7.4 for the data contents and 13.3 for the library default. The seed is the smallest of the three here.

Predict first. Two runs use the same seed and the same code but the training file was edited in place between them (12 labels corrected). Is the comparison valid?

A run record

Store, with every result, what is needed to repeat it:

  • a fingerprint of the data (a hash of its contents, or an immutable version id), not just a file name;
  • the split and its seed;
  • the preprocessing steps and their settings;
  • the model settings as actually used, defaults included (print them, do not assume);
  • library versions, and the code revision.
{"data": "9f3a07c1...", "split_seed": 3, "params": {"C": 1.0, "fit_intercept": true},
 "libs": {"fitlib": "1.4"}, "code": "a1b2c3d", "test_accuracy": 0.783}
Chapter context

Practical performance depends on the data boundary around training as much as on the estimator. Every learned preprocessing step is part of the model and must respect the same evaluation split.

Chapter reference: math, worked example & code

This section belongs to the whole chapter, so it is the same on every lesson in it and may cover a different lesson's topic. The code for the experiment you just ran is inside the experiment itself.

Math and notation

Treat the fitted object as preprocessing composed with prediction: model(x) = estimator(transform(x)). Fit both using the training data only. For an imbalanced binary task, report counts as well as rates so denominators remain visible.

Worked example

Training values [0,2] have mean 1. A test value is 100. If the mean is incorrectly fitted on all three values, it becomes 34. The test set has now changed the transformation applied to training examples. A separate 90-negative/10-positive dataset gives 90% accuracy but zero recall for always-negative predictions.

Reference code

The following example uses the Python standard library and does not call a remote service.

train, test = [0,2], [100]
assert sum(train)/len(train) == 1
assert sum(train+test)/len(train+test) == 34
assert 90/100 == .9
assert 0/10 == 0

Python examples are provided for study and local execution; this page does not execute Python.

Common mistakes

An excellent test score can reflect leakage. More hyperparameter trials can overfit a fixed validation set. Monitoring confidence alone does not measure real outcome quality.