Reproducible Randomness in NumPy

Intuition

Experiments must be repeatable: the same seed should give the same "random" data, so a teammate can reproduce your numbers. NumPy's modern API puts all randomness in a Generator object.

Precise explanation

  • rng = np.random.default_rng(seed) creates an independent generator (PCG64 by default).
  • rng.uniform(lo, hi, size=n), rng.normal(mu, sigma, size=n), rng.permutation(n), rng.integers(lo, hi, size=n).
  • Passing a generator around (rather than calling the legacy global np.random.seed) keeps different parts of a program from disturbing each other's streams.
  • Same seed → same numbers in the same NumPy version. NumPy reserves the right to change some algorithms between versions, so never hard-code random outputs in tests; test properties.

Synthetic linear data: x∼U(0,1)x \sim U(0, 1), y=2x+1+εy = 2x + 1 + \varepsilon, ε∼N(0,σ2)\varepsilon \sim N(0, \sigma^2).

Worked example

rng = np.random.default_rng(0)
idx = rng.permutation(10)       # some ordering of 0..9
test, train = idx[:3], idx[3:]  # 30 % test

Common mistakes

  • Calling default_rng(seed) inside a loop — every iteration restarts the same stream.
  • Using the global np.random.rand in library code.
  • Overlapping train and test indices.

Why this matters

Seeded data generation, shuffling and weight initialisation make every later ML, DL and FL exercise deterministic.

References