Random Numbers and Statistics
Simulate, resample, and summarize like a statistician
Random sampling, seeding, and built-in statistical tools power simulations, bootstraps, and null distributions — the practical half of statistical inference.
What you will learn
- Use default_rng with explicit seeds
- Draw from distributions for simulation
- Bootstrap confidence intervals with repeated resampling
What is this?
rng = np.random.default_rng(seed) is the modern random API; it draws from normal, binomial, poisson, and uniform distributions, permutes and samples arrays, and — crucially — is reproducible when seeded. numpy stats (mean, median, quantile, std, histogram) complement it, so whole simulations and bootstraps run in a few vectorized lines.
Why do you need it?
- Seeding makes every 'random' analysis reproducible and reviewable.
- Bootstrap CIs need no formulas — resampling estimates uncertainty directly.
- Null distributions for experiments are simulated, not assumed.
- Monte Carlo answers 'what if' questions exactly where formulas fall short.
Mental model
Re-running a dice-rolling board game with the same starting roll
Seeded random sampling
With a fixed seed, the 'random' dice land identically every session — debuggable and shareable. Without one, every replay tells a slightly different story and the analysis can't be audited. Bootstrap repeats the roll thousands of times to see how much the outcome wobbles.
How it works
- rng = np.random.default_rng(seed) isolates randomness; use it for all draws.
- rng.normal(mean, sd, n), rng.binomial(n_trials, p, n), rng.poisson(lam, n) generate scenarios.
- rng.choice(arr, size=k, replace=True) resamples for bootstraps; permutation shuffles arrays.
- np.histogram bins arrays for shape-checking; np.quantile reports percentiles.
- Resampling many draws and taking the 2.5%/97.5% quantiles yields a bootstrap CI.
Simulate → resample → infer.
Examples
Bootstrap a confidence interval
import numpy as nprng = np.random.default_rng(42)obs = rng.normal(100, 15, 200) boot = [obs[rng.choice(len(obs), size=len(obs), replace=True)].mean() for _ in range(1000)]lo, hi = np.quantile(boot, [0.025, 0.975])print("95% CI: %.1f .. %.1f" % (lo, hi))print("histogram:", np.histogram(boot, bins=5)[0])Repeated resampling with replacement builds the sampling distribution; 2.5%/97.5% quantiles bound the interval without formulas.
In production
- An experiment reviewer bootstraps lift CIs from per-user deltas instead of trusting normality.
- A demand planner simulates order volume with Poisson draws to size inventory buffers.
- A QA harness seeds random data so unit tests for aggregation logic are exactly repeatable.
Best practices
- Always seed — sharing an unseeded analysis invites unreproducible 'random' results.
- Use default_rng, not the legacy np.random global.
- Pin size and seed in a config so reruns match.
- Resample with replacement for bootstraps; sample without for splits.
Common mistakes
- Reusing np.random global state across functions, breaking isolation.
- Forgetting replace=True for bootstraps, silently shrinking effective samples.
- Seeding the wrong process so two 'independent' draws correlate.
- Interpreting a single simulation as 'the' answer rather than a draw from the distribution.
Debugging tips
- Two runs differ → a missing/duplicate seed somewhere in the call graph.
- A bootstrap CI is too narrow → resample size matches obs? replace=True? n draws enough?
- Simulation looks odd → compare np.histogram against the theoretical density.
- Exact reproducibility gate: run twice and diff the outputs — they must match.
Interview checkpoint
Hands-on lab
- Draw simulated experiment outcomes with default_rng
- Bootstrap a confidence interval for lift
- Assert reproducibility of the simulation
Simulate and Bootstrap a Conversion Impact
30 min · intermediate
Quick quiz
For a bootstrap you resample:
np.random.seed is the preferred modern way to seed randomness.