Random Number Generation
On this page
Randomness plays an essential role in data analysis and modeling. Whenever we simulate data, split datasets into training and testing parts, or add variability to models, we rely on random number generation. In data science and the digital humanities, randomness can model uncertainty — for instance, simulating missing historical data, estimating probabilities, or performing randomized sampling of texts or cultural artifacts.
NumPy provides a collection of tools for generating random numbers efficiently. These are found in the np.random module and can create data following different statistical distributions — mathematical descriptions of how values are spread out.
Let’s explore the most common ones and see how they can be visualized to understand their behavior.
Uniform Random Numbers: np.random.rand()
Under the continuous uniform model, equal-length intervals inside the range have equal probability. NumPy returns finite-precision pseudorandom values in the half-open interval [0, 1). The legacy np.random.rand() interface is retained here so you can read older notebooks; the local Generator interface follows in the statistical-reasoning lesson.
import numpy as np
uniform_values = np.random.rand(2, 3)
print(uniform_values)[[0.37454012 0.95071431 0.73199394]
[0.59865848 0.15601864 0.15599452]]
Each number here is random, drawn independently between 0 and 1. A computer uses a finite set of representable floating-point values; it does not generate infinite decimal precision. Uniform random numbers are useful for initializing parameters, shuffling data, or simulating equally probable outcomes — such as assigning random samples from a text corpus or modeling even distributions of events.
Integers in a Range: np.random.randint()
If you need random integers instead of floating-point numbers, NumPy provides the np.random.randint() function. This lets you define both the lower and upper limits of your range, as well as how many random numbers you want.
random_integers = np.random.randint(1, 100, size=10)
print(random_integers)[75 75 88 24 3 22 53 2 88 30]
Here, NumPy has generated 10 random integers between 1 (inclusive) and 100 (exclusive).
Random integers can generate simulated labels or experiment conditions. Repeated draws can collide, so this is not a guarantee of unique record identifiers. They can also create simulated categorical data — for example, generating random years of publication or ages of authors in a study.
Normal Distribution: np.random.randn()
The normal distribution, also called the Gaussian distribution or bell curve, is one of the most important concepts in statistics. It describes data that cluster around a mean (average) value, with most observations falling close to the mean and fewer appearing at the extremes. A normal distribution is a possible model for some measurements or errors, not a default law for cultural data. Do not assume word frequencies, sentence lengths or other observed quantities are normally distributed; inspect the measurement process and the actual distribution.
In NumPy, you can generate random numbers from a standard normal distribution (mean = 0, standard deviation = 1) using np.random.randn():
normal_values = np.random.randn(10)
print(normal_values)[-0.58087813 -0.52516981 -0.57138017 -0.92408284 -2.61254901 0.95036968
0.81644508 -1.523876 -0.42804606 -0.74240684]
Each value is randomly drawn from a distribution centered around 0, where most numbers fall between -1 and +1.
Normal models are useful in some inferential methods, but inference also uses other distributions and sampling designs. A generated bell shape establishes what the specified simulation produces; it does not validate a model of language, authorship or historical measurement.
Visualizing Random Data
Data visualization helps us see the behavior of random numbers. Let’s generate a large set of normally distributed numbers and visualize their frequency using a histogram — a plot showing how often values fall into certain ranges (or “bins”).
import numpy as np
import matplotlib.pyplot as plt
random_numbers = np.random.randn(1000)
plt.figure(figsize=(8, 5))
plt.hist(random_numbers, bins=30, color='steelblue', edgecolor='black')
plt.title('Distribution of Random Numbers (Standard Normal)')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.grid(True)
plt.show()This produces a histogram of finite simulated counts. Its bins fluctuate around a bell-shaped pattern; the plotted bars are not a smooth probability density.
The symmetry around zero reflects the normal distribution’s property that positive and negative deviations are equally likely. The shape here follows from the chosen normal generator. A histogram of actual measurements can reveal skewness, multiple groups or other departures; neither symmetry nor a familiar shape proves a particular data-generating process.
Histograms like this are essential for exploring any dataset, helping us identify whether our data follow a normal, skewed, or irregular distribution.
Randomness, Seeding
Randomness is important in data analysis. It lets analysts simulate real-world variation, sample data, and test ideas when full datasets are unavailable. In Python, NumPy can generate random numbers for such tasks — from testing models to estimating missing information.
Because these numbers are generated by algorithms, they are pseudorandom, not truly random. To make results reproducible (so they stay the same each time), NumPy allows the use of a seed.
import numpy as np
np.random.seed(42)
print(np.random.rand(3))[0.37454012 0.95071431 0.73199394]
A seed reproduces a stream only with the same generator, compatible implementation and sequence of calls. Save the software versions and call order as well as the seed. New examples should prefer a local generator so another cell cannot silently alter shared random state.
Example Project: Synthetic Temperature Measurements
The example below shows how randomness and visualization work together in data analysis. Here, NumPy generates invented temperature-like measurements to inspect a specified normal model. These are not climate observations, a global temperature series or a reconstruction of missing climate records. The Matplotlib library is used to display the results — visualization will be discussed in more detail later in this book.
The simulation draws 1,000 values from the chosen normal distribution. Its population parameters are 14 °C and 3 °C; the displayed sample summaries are about 14.06 °C and 2.94 °C in the recorded run. The generating parameters are a chosen mean of 14 °C and standard deviation of 3 °C. The sample mean and standard deviation vary between draws. These arbitrary teaching parameters have no claimed empirical climate calibration.
import numpy as np
import matplotlib.pyplot as plt
# Set seed for reproducibility
np.random.seed(42)
# Generate 1,000 random temperatures (mean=14°C, std=3°C)
temperatures = np.random.normal(14, 3, 1000)
# Compute simple statistics
print(f"Average temperature: {np.mean(temperatures):.2f} °C")
print(f"Standard deviation: {np.std(temperatures):.2f} °C")
# Plot a sample (first 200 records)
plt.figure(figsize=(9, 4))
plt.plot(temperatures[:200], color='orange')
plt.title('Synthetic Independent Temperature-Like Draws')
plt.xlabel('Record Index')
plt.ylabel('Temperature (°C)')
plt.grid(True)
plt.show()Average temperature: 14.06 °C
Standard deviation: 2.94 °C
The line plot above shows the first 200 simulated temperature points. Each point represents one temperature record in the sequence. The jagged orange curve reflects random draws under this model. Record index is draw order, not an observed date. Connecting adjacent draws does not introduce seasonality, temporal dependence or a climate trend.
In this small experiment:
- The average temperature (14.06 °C) represents the central tendency — it tells what a “typical” value looks like.
- The standard deviation (2.94 °C) describes how much the temperatures differ from the average. A small standard deviation means most values are close to the average (the data are stable), while a large one means the values are more spread out (the data vary more).
For a normal model, approximately 68% of its probability lies within one population standard deviation of its mean. A finite generated sample need not match that proportion exactly. This experiment teaches simulation and plotting; it does not establish how real environmental observations behave. See the NumPy normal-generator reference for the model definition. Change the generating spread and predict how the histogram changes before running again.