Random numbers
A random number generator
import numpy as np
rng = np.random.default_rng()
print(rng.integers(1, 7, size=10)) # ten dice rolls: 1 to 6
print(rng.random(3)) # three floats between 0 and 1Create a Generator with np.random.default_rng() and ask it for numbers. In integers(low, high), high is not included, so integers(1, 7) gives 1 to 6. Run it again: different numbers every time.
Repeatable randomness: the seed
import numpy as np
a = np.random.default_rng(seed=42).integers(1, 100, size=5)
b = np.random.default_rng(seed=42).integers(1, 100, size=5)
print(a)
print(b)
print((a == b).all()) # True: the same seed gives the same numbersComputers produce pseudo-random numbers from a starting value, the seed. The same seed always gives the same sequence, which makes experiments, tests and shared notebooks reproducible.
Distributions
import numpy as np
rng = np.random.default_rng(7)
uniform = rng.uniform(10, 20, size=5) # any value between 10 and 20, equally likely
heights = rng.normal(loc=170, scale=8, size=10_000) # the bell curve: mean 170, spread 8
print(np.round(uniform, 2))
print(round(heights.mean(), 1), round(heights.std(), 1)) # close to 170 and 8
print(round(((heights > 162) & (heights < 178)).mean(), 2)) # about 0.68 within one spread of the meanThe normal distribution describes many natural measurements. About 68% of values fall within one standard deviation of the mean, as the last line shows.
Choosing and shuffling
import numpy as np
rng = np.random.default_rng(3)
names = np.array(["Asha", "Leo", "Mei", "Raj", "Zoe"])
print(rng.choice(names)) # one at random
print(rng.choice(names, size=3, replace=False)) # three different people
print(rng.permutation(names)) # a shuffled copy
print(rng.choice(["heads", "tails"], size=6, p=[0.5, 0.5]))replace=False means each item can be picked only once, like drawing names from a hat. p gives the probability of each option.
Simulating dice
import numpy as np
rng = np.random.default_rng(1)
rolls = rng.integers(1, 7, size=(100_000, 2)) # 100,000 throws of two dice
totals = rolls.sum(axis=1)
values, counts = np.unique(totals, return_counts=True)
for v, c in zip(values, counts):
print(f"{v:2} {c / len(totals):.3f} {'#' * int(c / len(totals) * 200)}")Seven is the most common total, with a probability of 6/36, about 0.167, and the simulation lands close to it.
Estimating pi
import numpy as np
rng = np.random.default_rng(2026)
points = rng.random((1_000_000, 2)) # random points in a 1 x 1 square
inside = (points ** 2).sum(axis=1) <= 1 # inside the quarter circle?
print(4 * inside.mean()) # close to 3.14159A quarter circle of radius 1 covers pi/4 of the unit square, so four times the fraction of points that land inside it approximates pi. This technique, using random sampling to estimate an answer, is called a Monte Carlo method.