CodeRigor

FREE LESSON

Seeds, splits & train-only transforms

Local random generators, disjoint dataset splits and preprocessing learned only from training data.

A seed is a reproducibility aid, not a source of statistical independence or a complete experiment description. Record code, data, configuration and package versions too. Give each experiment a local random generator instead of changing a process-wide random stream used by unrelated code.

The test split receives fitted preprocessing parameters, but does not contribute to fitting them.

Split before fitting preprocessing
Fit the mean and scale only on training rows. Development and test rows use those fixed parameters; no held-out row points back into fitting.
Split before fitting preprocessing
Fit the mean and scale only on training rows. Development and test rows use those fixed parameters; no held-out row points back into fitting.
Python
import numpy as np

a = np.random.default_rng(7).permutation(6)
b = np.random.default_rng(7).permutation(6)
print(np.array_equal(a, b))
print(sorted(a.tolist()))

Split before fitting preprocessing or selecting thresholds. Training data fits parameters; development data chooses approaches; held-out test data estimates the final result. Repeatedly choosing based on a test set turns it into another development set. Grouped or temporally related examples may require a grouped or chronological split; a random index split alone does not prevent that leakage.

Python
import numpy as np

train = np.array([[0.0, 2.0], [2.0, 2.0]])
mean = train.mean(axis=0)
scale = train.std(axis=0)  # population standard deviation here
scale = np.where(scale == 0, 1.0, scale)
heldout = np.array([[10.0, 2.0]])
print((heldout - mean) / scale)

Fitting mean/scale on combined train and held-out rows leaks test distribution information. Transforming the held-out rows with training parameters is fine. Constant training features use scale one, keeping outputs finite without forcing held-out values to zero. This exercise uses ddof=0 by contract.

One local seeded permutation can be sliced into adjacent, nonoverlapping ranges without touching a global random stream.

One permutation, disjoint slices
For n=6, n_train=3 and n_dev=1, every index appears once. The remaining two indices form the test split.
One permutation, disjoint slices
For n=6, n_train=3 and n_dev=1, every index appears once. The remaining two indices form the test split.

The build splits a permutation once into explicit counts and returns reusable training parameters. Check complete coverage, no overlap, same-seed equality, unchanged global RNG state and held-out values far outside the training range. The last case makes leakage visible even when ordinary examples look correct.

Watch & read

Free lectures, talks and readings that cover this skill from another angle. All resources →

Focus on separating fitting, model selection and final evaluation. This lesson uses seeded disjoint splits and training-only preprocessing rather than implementing k-fold cross-validation.