3.3. Random Number Generation#

Hide code cell source

import numpy as np

3.3.1. The numpy.random module#

(These functions discussed in this section are considered “legacy random generation” and are for simple random data and for instructional purposes. The next section provides some information about the new random modules in numpy for your information.)

The numpy.random module in NumPy provides tools for generating pseudo-random numbers and sampling from various probability distributions. Some functions in the numpy.random module are commonly used:

  • np.random.rand(): returns random floating-point numbers (uniform distribution over the interval [0, 1))

  • np.random.randn(): returns random floating-point numbers (standard normal distribution with mean of 0 and standard deviation of 1) (note that np.random.random is the same as random.rand(), except random.random() takes the shape argument as a single tuple; e.g., see stackoverflow)

  • np.random.randint(): returns random integers from a specified range

As a summary, here’s a comparison table of the commonly used methods in the numpy random module:

Function

Distribution

Typical Use

Note

Example

rand

Uniform [0,1)

Random decimals

uniform decimals

np.random.rand()

random

Uniform [0,1)

Same as rand

uniform decimals

np.random.random(size=(2, 3))

randn

Normal (0,1)

Stats, ML

bell curve; mean=0, SD=1

np.random.randn()

normal

Normal (μ, σ)

Simulations

bell curve; mean & SD controllable

np.random.normal(10, 2)

randint

Integers

Dice, indexing

whole numbers

np.random.randint(1, 7)

Simple examples of the random numbers are:

3.3.1.1. random.rand( )#

np.random.rand()            ### rand: one number
np.random.rand(3)           ### rand: 1D array
np.random.rand(2, 3)        ### rand: 2D
array([[0.25585576, 0.47474593, 0.7351624 ],
       [0.50715569, 0.35688069, 0.61515629]])

3.3.1.2. random.random()#

np.random.random()          ### random: one number
np.random.random(3)         ### random: 1D array
np.random.random((2, 3))    ### random: 2D
np.random.random(size=(2, 3))    ### random: 2D
array([[0.94534247, 0.56306382, 0.97653082],
       [0.03571704, 0.44155253, 0.24241619]])

3.3.1.3. random.randn( )#

np.random.randn()           ### randn: 1 number, normal distribution
np.random.randn(3)          ### randn: 1D array, normal distribution
np.random.randn(2, 3)       ### randn: 2D array, normal distribution
# np.random.randn(2, 3, 4)    ### randn: 3D array, normal distribution
# np.random.randn(2, 5, 2, 3)   ### randn: 4D array, normal distribution
array([[ 0.62773018,  0.56831717,  0.70808694],
       [ 0.93679683,  1.54135362, -0.28017495]])

3.3.1.4. random.normal()#

np.random.normal(loc=0.0, scale=1.0, size=None)

loc = location of mean

np.random.normal()        ### normal: one number, normal distribution
np.random.normal(3)       ### normal: one number, mean=3
np.random.normal(0, 1)    ### normal: mean=0, std=1
np.random.normal(loc=0, scale=1)    ### normal: mean=0, std=1
np.random.normal(0, 1, (2, 3))  ### normal: mean=0, std=1, shape=(2,3)
# create a 3x3 array of normally distributed pseudorandom
# values with mean 0 and standard deviation 1
array([[ 0.56279017, -1.06860216, -0.62864322],
       [ 0.26431131,  0.06628755,  0.38196776]])

3.3.1.5. random.randint( )#

np.random.randint( 10 )             ### 0 to 10 exclusive
np.random.randint( 5, 10 )          ### 5 to 10 exclusive
np.random.randint(5, 10, (3, 3))    ### normal: mean=0, std=1, shape=(3,3)
array([[6, 9, 7],
       [5, 7, 5],
       [9, 7, 8]])

3.3.1.6. choice( )#

np.random.choice([1, 2, 3, 4, 5], size = 2)  ### the choice function
array([5, 5])

3.3.1.7. size#

np.random.choice([3, 5, 7, 9], size=(3, 5)) ### the size parameter to generate N-D arrays
array([[9, 5, 9, 5, 9],
       [3, 7, 7, 5, 7],
       [3, 9, 7, 3, 3]])

3.3.1.8. rng.choice( )#

The modern form of choice() uses a random number generator, rng, instead of np.random:

rng.choice(a, size=None, replace=True, p=None)

  • a: the values to draw from (a list, an array, or a pandas column)

  • size: how many values to draw

  • replace: whether a value can be drawn more than once (default True)

  • p: the probability of drawing each value; without it, every value is equally likely

The seed in default_rng(42) makes the results the same every time the cell runs. You will use rng.choice() with p in Chapter 8 to simulate outcomes from a probability model.

rng = np.random.default_rng(42)       ### create a generator with seed 42
rng.choice([1, 2, 3, 4, 5], size=2)  ### same as np.random.choice
rng.choice(['on time', 'late'], size=10, p=[0.9, 0.1])  ### p: 90% on time, 10% late
array(['on time', 'on time', 'on time', 'on time', 'late', 'on time',
       'on time', 'on time', 'on time', 'on time'], dtype='<U7')

This section is for informational purposes only.

This section compares NumPy’s legacy random number generator with modern Generator API for reproducible randomness.

Topic

Legacy (global RNG)

Modern (Generator API)

Main objects

np.random module, RandomState

np.random.Generator (e.g., rng = default_rng(seed))

Seeding

np.random.seed(123) (global)

rng = np.random.default_rng(123) (local, explicit)

State scope

Global, shared across code

Isolated per rng, easy to pass around

Typical calls

np.random.rand, randn, randint, random_sample

rng.random, normal, integers, uniform, …

Reproducibility

Fragile (any call anywhere advances global state)

Robust (each rng advances its own state only)

Performance/algorithms

Older (MT19937); OK speed

Newer bit-generators (PCG64 default), often faster/better

Broadcasting/shape

Functions accept size= or separate dims (rand(2,3))

Consistent size= tuple; parameters broadcast cleanly

Thread/process safety

Global contention possible

Use separate Generators per thread/process

Legacy

Modern (preferred)

np.random.seed(123)

rng = np.random.default_rng(123)

np.random.rand(2,3)

rng.random((2,3))

np.random.randn(5)

rng.normal(loc=0, scale=1, size=5)

np.random.randint(0, 10, 4)

rng.integers(0, 10, size=4) (note: high exclusive)

np.random.random_sample(3) / np.random.sample(3)

rng.random(3)

np.random.uniform(-1, 1, 100)

rng.uniform(-1, 1, size=100)

np.random.binomial(n=10, p=0.3, size=6)

rng.binomial(10, 0.3, size=6)

np.random.poisson(lam=5, size=(3,3))

rng.poisson(5, size=(3,3))

np.random.permutation(n)

rng.permutation(n)

np.random.shuffle(a)

rng.shuffle(a)

Call / Purpose

Legacy (global RNG)

Modern (Generator API)

Example (legacy → modern)

Seed

random.seed(123)

rng = random.default_rng(123)

random.seed(123) → rng = random.default_rng(123)

Uniform floats

random.rand(2, 3)

rng.random((2, 3))

random.rand(2,3) → rng.random((2,3))

Standard normal

random.randn(5)

rng.normal(0, 1, size=5)

random.randn(5) → rng.normal(0,1,5)

Integers

random.randint(0, 10, 4)

rng.integers(0, 10, size=4)

random.randint(0,10,4) → rng.integers(0,10,4) (high is exclusive)

Random sample / sample alias

random.random_sample(3) (= random.sample(3))

rng.random(3)

random.random_sample(3) → rng.random(3)

Uniform in [low, high)

random.uniform(-1, 1, 6)

rng.uniform(-1, 1, size=6)

random.uniform(-1,1,6) → rng.uniform(-1,1,6)

Binomial

random.binomial(10, 0.3, size=6)

rng.binomial(10, 0.3, size=6)

random.binomial(10,0.3,6) → rng.binomial(10,0.3,6)

Poisson

random.poisson(5, size=(3, 3))

rng.poisson(5, size=(3,3))

random.poisson(5,(3,3)) → rng.poisson(5,(3,3))

Permutation (returns permuted copy)

random.permutation(10)

rng.permutation(10)

random.permutation(10) → rng.permutation(10)

Shuffle (in place)

random.shuffle(a)

rng.shuffle(a)

random.shuffle(a) → rng.shuffle(a)

3.3.2. Quick Reference: Modern Random API#

Use the modern generator API when you need reproducible random values for sampling or simulation.

rng = np.random.default_rng(42)
rng.random(5)                 # uniform [0, 1)
rng.integers(1, 10, size=5)   # integers
rng.normal(0, 1, size=5)      # normal values
rng.choice([1, 2, 3], size=2) # sample values
rng.permutation(5)            # permuted indexes
rng.uniform(5, 10, size=3)    # uniform range

3.3.3. Section Practice#

Use this short exercise to check the main workflow from this section.

### Exercise: Practice Random Number Generation
# Create a list named monthly_sales with the values 120, 135, 150, and 145.
# Calculate the average monthly sales and print it rounded to one decimal place.
### Your code starts here




### Your code ends here

Hide code cell source

### Solution
monthly_sales = [120, 135, 150, 145]
average_sales = sum(monthly_sales) / len(monthly_sales)
print(round(average_sales, 1))
137.5
### Solution
monthly_sales = [120, 135, 150, 145]
average_sales = sum(monthly_sales) / len(monthly_sales)
print(round(average_sales, 1))
137.5