Dictionary of Applied Machine Learning · random variable (RV)

random variable (RV) — Python demo

Numerical companion to the entry random variable (RV): it recomputes what the entry states and prints one line per check

One block per paragraph of the entry (marked [P...]), in order: each block verifies numerically what the corresponding paragraph asserts. Self-contained (numpy/matplotlib only), fixed seed.

Run it without installing anything:
uv run https://dictionaryofml.org/terms/rv.py
uv downloads this script and the pinned NumPy and Matplotlib it needs, then runs it; the script fetches any input file it uses. To keep the output files, download rv.py into a folder and run uv run rv.py there. With NumPy and Matplotlib already installed, python3 rv.py, from any directory — it writes its output files into the current directory. Fixed seeds, so the printed numbers reproduce exactly. Download rv.py · Notebook · Open in Colab

The script, block by block

One cell per block of the script: the code, and what that code printed when it last ran here

setup

"""
rv.py — numerical companion to the glossary entry 'random variable (RV)'.

One block per paragraph of the entry (marked [P...]), in order: each block
verifies numerically what the corresponding paragraph asserts. Self-contained
(numpy/matplotlib only), fixed seed.

Blocks
------
[P-weather] The maximum daytime temperature in Krems, read at 13:00, is a
            real-valued RV; each day is one outcome of a random experiment and
            the recorded temperature is a single realization. Thirty days are
            modeled as iid RVs with a common distribution; the realizations are
            written to rv_stem.csv for the entry's stem-plot figure.
[P-def]     An RV is a function on the sample space of a random experiment: for
            a fair-die experiment (sample space {1,...,6}) the RV
            x(omega) = 1{omega is even} is an explicit function; simulating the
            experiment and applying the function reproduces the probability
            P(x = 1) = 1/2 implied by the uniform distribution on the sample
            space.
[P-types]   The types listed in the entry — binary RV, discrete RV, real-valued
            RV, random vector, random matrix — are instantiated as functions of
            the same underlying experiment, with values in {0, 1}, a countable
            set, R, R^d, and R^{m x d}, respectively.

Outputs
-------
rv_stem.csv : figure data for the entry's pgfplots stem plot (day, temp).
rv.png      : preview figure (checking only).

Data generated by pythondemos/rv.py.
"""

import numpy as np
import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
from pathlib import Path

OUT_DIR = Path(__file__).parent

rng = np.random.default_rng(42)
report = []


def check(name, ok):
    report.append((name, bool(ok)))
    print(f"  [{'ok' if ok else 'FAIL'}] {name}")

P-weather

The maximum daytime temperature in Krems, read at 13:00, is a real-valued RV; each day is one outcome of a random experiment and the recorded temperature is a single realization. Thirty days are modeled as iid RVs with a common distribution; the realizations are written to rv_stem.csv for the entry's stem-plot figure.

print("[P-weather] daily 13:00 temperatures as realizations of a real-valued RV")
mu, sigma = 20.0, 4.0                 # center and spread of the common distribution (degC)
n_days = 30
days = np.arange(1, n_days + 1)
temps = mu + sigma * rng.standard_normal(n_days)
np.savetxt(OUT_DIR / "rv_stem.csv",
           np.column_stack([days, temps]),
           fmt=["%d", "%.3f"], delimiter=",",
           header="day,temp", comments="")
check("one realization written per day", days.size == n_days)
check("every realization is a finite real number", np.all(np.isfinite(temps)))
[P-weather] daily 13:00 temperatures as realizations of a real-valued RV
  [ok] one realization written per day
  [ok] every realization is a finite real number

P-def

An RV is a function on the sample space of a random experiment: for a fair-die experiment (sample space {1,...,6}) the RV x(omega) = 1{omega is even} is an explicit function; simulating the experiment and applying the function reproduces the probability P(x = 1) = 1/2 implied by the uniform distribution on the sample space.

print("[P-def] an RV is a function on the sample space")
sample_space = np.arange(1, 7)                   # fair die
x_of = lambda omega: (omega % 2 == 0).astype(int)  # RV: even -> 1
outcomes = rng.choice(sample_space, size=10**6)  # run the experiment
x_real = x_of(outcomes)                          # realizations of the RV
check("x is a deterministic function of the outcome",
      np.array_equal(x_real, x_of(outcomes)))
check("P(x = 1) = 1/2 from the uniform experiment",
      abs(x_real.mean() - 0.5) < 2e-3)
check("the same outcome always maps to the same value",
      x_of(np.array([4]))[0] == 1 and x_of(np.array([3]))[0] == 0)
[P-def] an RV is a function on the sample space
  [ok] x is a deterministic function of the outcome
  [ok] P(x = 1) = 1/2 from the uniform experiment
  [ok] the same outcome always maps to the same value

P-types

The types listed in the entry — binary RV, discrete RV, real-valued RV, random vector, random matrix — are instantiated as functions of the same underlying experiment, with values in {0, 1}, a countable set, R, R^d, and R^{m x d}, respectively.

print("[P-types] binary / discrete / real-valued / vector / matrix RVs")
omega = rng.uniform(size=10**4)                  # one underlying experiment
binary = (omega > 0.5).astype(int)
discrete = np.floor(10 * omega).astype(int)      # values in {0,...,9}
realval = -np.log(omega)                         # values in R
vec = np.stack([omega, omega**2, np.sin(omega)], axis=1)      # R^3
mat = omega[:, None, None] * np.ones((1, 2, 3))               # R^{2x3}
check("binary RV takes values in {0, 1}",
      set(np.unique(binary)) <= {0, 1})
check("discrete RV takes values in a countable set",
      np.issubdtype(discrete.dtype, np.integer)
      and len(np.unique(discrete)) <= 10)
check("real-valued RV takes values in R (nonnegative here)",
      realval.dtype == float and np.all(realval >= 0))
check("random vector maps outcomes to R^3", vec.shape == (10**4, 3))
check("random matrix maps outcomes to R^{2x3}",
      mat.shape == (10**4, 2, 3))

# ------------------------------------------------------------ preview
# The temperatures, the die outcomes, and the RV values live on different
# sets, so they get one panel each: drawing them on shared x positions
# would hide one series.
fig, ax = plt.subplots(1, 3, figsize=(11.0, 3.0))
markerline, stemlines, baseline = ax[0].stem(days, temps)
plt.setp(markerline, markersize=4)
plt.setp(baseline, visible=False)
ax[0].set_xlabel("day")
ax[0].set_ylabel("temperature at 13:00 (degC)")
ax[0].set_title("[P-weather] daily 13:00 temperatures")
vals, counts = np.unique(outcomes[:600], return_counts=True)
ax[1].bar(vals, counts / 600, width=0.6, color="0.75", edgecolor="black")
ax[1].set_xticks(range(1, 7))
ax[1].set_xlabel("outcome of the die roll")
ax[1].set_ylabel("relative frequency")
ax[1].set_title("[P-def] the 6 outcomes")
ax[2].bar([0, 1], [np.mean(x_real == 0), np.mean(x_real == 1)],
          width=0.6, color="white", edgecolor="black", hatch="///")
ax[2].set_xticks([0, 1])
ax[2].set_xlabel("value of the RV 1{even}")
ax[2].set_ylabel("relative frequency")
ax[2].set_title("[P-def] the 2 values it takes")
fig.tight_layout()
fig.savefig(OUT_DIR / "rv.png", dpi=110)
print(f"\n{sum(ok for _, ok in report)}/{len(report)} checks passed")
assert all(ok for _, ok in report)
[P-types] binary / discrete / real-valued / vector / matrix RVs
  [ok] binary RV takes values in {0, 1}
  [ok] discrete RV takes values in a countable set
  [ok] real-valued RV takes values in R (nonnegative here)
  [ok] random vector maps outcomes to R^3
  [ok] random matrix maps outcomes to R^{2x3}

10/10 checks passed
Preview figure produced by rv.py
The preview figure the block P-types writes when the script runs