# 16.8. Distributions¶

Now that we have learned about how to work with probability theory in both discrete and continuous setting, lets get to know some of the common random distributions encountered. Depending on the area of machine learning we are working in, we may potentially need to be familiar with vastly more of these, or for some areas of deep learning potentially none at all. This is, however, a good basic list to be familiar with. Let’s first import some common libraries.

%matplotlib inline
import d2l
from IPython import display
from math import erf, factorial
import numpy as np


## 16.8.1. Bernoulli¶

This is the simplest random variable usually encountered. This is the random variable that encodes a coin flip which comes up $$1$$ with probability $$p$$ and $$0$$ with probability $$1-p$$. If we have a random variable with this distribution, we will write

(16.8.1)$X \sim \mathrm{Bernoulli}(p).$

The cumulative distribution function is

(16.8.2)$\begin{split}F(x) = \begin{cases} 0 & x < 0, \\ 1-p & 0 \le x < 1, \\ 1 & x >= 1 . \end{cases}\end{split}$

The probability mass function is plotted below.

p = 0.3

d2l.set_figsize()
d2l.plt.stem([0, 1], [1 - p, p], use_line_collection=True)
d2l.plt.xlabel('x')
d2l.plt.ylabel('p.m.f.')
d2l.plt.show() Now, let us plot the cumulative distribution function.

x = np.arange(-1, 2, 0.01)
F = lambda x: 0 if x < 0 else 1 if x > 1 else 1 - p

d2l.plot(x, np.array([F(y) for y in x]), 'x', 'c.d.f.') If $$X \sim \mathrm{Bernoulli}(p)$$, then:

• $$\mu_X = p$$,

• $$\sigma_X^2 = p(1-p)$$.

We can sample an array of arbitrary shape from a Bernoulli random variable as follows.

1*(np.random.rand(10, 10) < p)

array([[0, 0, 0, 0, 0, 1, 0, 1, 1, 0],
[1, 0, 1, 0, 0, 0, 1, 0, 1, 1],
[1, 1, 0, 1, 1, 1, 0, 1, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[1, 0, 0, 0, 0, 1, 1, 1, 0, 0],
[0, 0, 0, 1, 1, 1, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 1, 1, 0, 1],
[0, 1, 0, 1, 1, 1, 0, 1, 0, 0],
[1, 0, 0, 1, 1, 1, 1, 0, 1, 0]])


## 16.8.2. Discrete Uniform¶

The next random variable encountered is a discrete uniform distribution. For our discussion here, we will assume that it is on the integers $$\{1,2,\ldots, n\}$$, however any other set of values can be freely chosen. The meaning of the word uniform in this context is that every possible value is equally likely. The probability for each value $$i \in \{1,2,3,\ldots,n\}$$ is $$p_i = \frac{1}{n}$$. We will denote this relationship as

(16.8.3)$X \sim \mathrm{Uniform}(n).$

The cumulative distribution function is

(16.8.4)$\begin{split}F(x) = \begin{cases} 0 & x < 1, \\ \frac{k}{n} & k \le x < k+1 \text{ with } 1 \le k < n, \\ 1 & x >= n . \end{cases}\end{split}$

Let us first plot the probabilty mass function.

n = 5

d2l.plt.stem([i+1 for i in range(n)], n*[1 / n], use_line_collection=True)
d2l.plt.xlabel('x')
d2l.plt.ylabel('p.m.f.')
d2l.plt.show() Now, let us plot the cumulative distribution function.

x = np.arange(-1, 6, 0.01)
F = lambda x: 0 if x < 1 else 1 if x > n else np.floor(x) / n

d2l.plot(x, np.array([F(y) for y in x]), 'x', 'c.d.f.') If $$X \sim \mathrm{Uniform}(n)$$, then:

• $$\mu_X = \frac{1+n}{2}$$,

• $$\sigma_X^2 = \frac{n^2-1}{12}$$.

We can an array of arbitrary shape from a discrete uniform random variable as follows. Note that the range

np.random.random_integers(1, n, size=(10, 10))

/var/lib/jenkins/miniconda3/envs/d2l-en-numpy2-0/lib/python3.7/site-packages/ipykernel_launcher.py:1: DeprecationWarning: This function is deprecated. Please call randint(1, 5 + 1) instead
"""Entry point for launching an IPython kernel.

array([[3, 4, 5, 2, 1, 3, 1, 3, 5, 1],
[1, 3, 3, 3, 2, 1, 1, 5, 2, 2],
[2, 4, 1, 4, 3, 4, 2, 3, 3, 3],
[1, 3, 2, 1, 1, 1, 4, 4, 5, 2],
[5, 1, 2, 4, 2, 2, 2, 1, 4, 2],
[1, 4, 2, 1, 5, 4, 4, 5, 1, 1],
[1, 4, 3, 3, 2, 5, 2, 4, 4, 2],
[2, 4, 3, 5, 4, 3, 5, 2, 5, 4],
[3, 3, 3, 5, 5, 4, 3, 2, 3, 2],
[5, 4, 1, 4, 3, 1, 2, 5, 1, 4]])


## 16.8.3. Continuous Uniform¶

Next let us discuss the continuous uniform distribution. The idea behind this random variable is that if we increase the $$n$$ in the previous distribution, and then scale it to fit within the interval $$[a,b]$$, we will approach a continuous random variable that just picks an arbitrary value in $$[a,b]$$ all with equal probability. We will denote this distribution as

(16.8.5)$X \sim \mathrm{Uniform}([a,b]).$

The probability density function is

(16.8.6)$\begin{split}p(x) = \begin{cases} \frac{1}{b-a} & x \in [a,b], \\ 0 & x \not\in [a,b]. \end{cases}\end{split}$

The cumulative distribution function is

(16.8.7)$\begin{split}F(x) = \begin{cases} 0 & x < a, \\ \frac{x-a}{b-a} & x \in [a,b], \\ 1 & x >= b . \end{cases}\end{split}$

Let us first plot the probabilty density function.

a = 1; b = 3

x = np.arange(0, 4, 0.01)
p = (x > a)*(x < b)/(b - a)

d2l.plot(x, p, 'x', 'p.d.f.') Now, let us plot the cumulative distribution function.

F = lambda x: 0 if x < a else 1 if x > b else (x - a) / (b - a)

d2l.plot(x, np.array([F(y) for y in x]), 'x', 'c.d.f.') If $$X \sim \mathrm{Uniform}([a,b])$$, then:

• $$\mu_X = \frac{a+b}{2}$$,

• $$\sigma_X^2 = \frac{(b-a)^2}{12}$$.

We can an array of arbitrary shape from a uniform random variable as follows. Note that it by default samples from a $$\mathrm{Uniform}([a,b])$$, so if we want a different range we need to scale it.

(b - a) * np.random.rand(10, 10) + a

array([[1.97863545, 2.19450855, 1.07654626, 1.47644602, 1.24225098,
1.41514747, 1.30560456, 1.32237796, 2.56736606, 2.35569971],
[1.13285511, 1.66747206, 1.00935121, 1.65552948, 2.83082254,
1.59803672, 1.27982038, 2.05899742, 1.44309463, 2.71594239],
[2.40546113, 2.81293025, 1.94324496, 2.08172079, 1.56761007,
1.39812837, 1.60949606, 1.25130137, 2.06889312, 2.4447495 ],
[2.63942405, 1.68514547, 1.96110155, 1.76573757, 2.04322633,
2.10628951, 1.42376643, 2.44424897, 2.97011143, 2.57180954],
[1.77310147, 1.84672146, 2.32683545, 2.74585997, 2.88942827,
1.02166986, 2.29433428, 2.1629317 , 1.06540308, 2.77064838],
[2.99585323, 1.38269222, 1.74415853, 2.93155375, 2.43913259,
1.52552717, 1.07653743, 1.51226967, 2.43689424, 2.46427841],
[1.28680264, 1.60810716, 1.81830373, 2.05617726, 2.63414142,
2.56777828, 2.71815194, 2.93125459, 2.0281178 , 1.21856788],
[1.88541515, 2.27727245, 1.05775259, 2.81159144, 1.95347226,
2.4153804 , 2.33073618, 1.59514593, 1.39773888, 1.73778526],
[1.14210304, 1.16283585, 2.15379447, 2.01919932, 1.14323683,
1.29073976, 2.10812538, 2.99692759, 2.4785342 , 2.75779667],
[1.622822  , 2.49068741, 2.55102505, 1.83224874, 2.93238589,
1.33181034, 1.85743828, 2.29555114, 2.04772667, 2.87794657]])


## 16.8.4. Binomial¶

Let us make things a little more complex and examine the binomial random variable. This random variable originates from performing a sequence of $$n$$ independent experiments, each of which have probability $$p$$ of succeeding, and asking how many successes we expect to see.

Let us express this mathematically. Each experiment is an independent random variable $$X_i$$ where we will use $$1$$ to encode success, and $$0$$ to encode failure. Since each is an independent coin flip which is successful with probability $$p$$, we can say that $$X_i \sim \mathrm{Bernoulli}(p)$$. Then, the binomial random variable is

(16.8.8)$X = \sum_{i=1}^n X_i.$

In this case, we will write

(16.8.9)$X \sim \mathrm{Binomial}(n,p).$

To get the cumulative distribution function, we need to notice that getting exactly $$k$$ successes can occur in $$\binom{n}{k} = \frac{n!}{k!(n-k)!}$$ ways each of which has a probability of $$p^m(1-p)^{n-m}$$ of occuring. Thus the cumulative distribution function is

(16.8.10)$\begin{split}F(x) = \begin{cases} 0 & x < 0, \\ \sum_{m \le k} \binom{n}{m} p^m(1-p)^{n-m} & k \le x < k+1 \text{ with } 0 \le k < n, \\ 1 & x >= n . \end{cases}\end{split}$

Let us first plot the probabilty mass function.

n = 10
p = 0.2

# Compute binomial coefficient
def binom(n, k):
comb = 1
for i in range(min(k, n - k)):
comb = comb * (n - i) // (i + 1)
return comb

pmf = np.array([p**i * (1-p)**(n - i) * binom(n, i) for i in range(n + 1)])

d2l.plt.stem([i for i in range(n + 1)], pmf, use_line_collection=True)
d2l.plt.xlabel('x')
d2l.plt.ylabel('p.m.f.')
d2l.plt.show() Now, let us plot the cumulative distribution function.

x = np.arange(-1, 11, 0.01)
cmf = np.cumsum(pmf)
F = lambda x: 0 if x < 0 else 1 if x > n else cmf[int(x)]

d2l.plot(x, np.array([F(y) for y in x.tolist()]), 'x', 'c.d.f.') While this result is not simple, the means and variances are. If $$X \sim \mathrm{Binomial}(n,p)$$, then:

• $$\mu_X = np$$,

• $$\sigma_X^2 = np(1-p)$$.

This can be sampled as follows.

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

array([[2, 2, 2, 1, 2, 1, 0, 2, 0, 0],
[3, 2, 1, 1, 2, 4, 4, 0, 2, 5],
[2, 1, 1, 2, 4, 3, 3, 2, 3, 0],
[0, 4, 3, 0, 4, 2, 1, 1, 2, 5],
[1, 4, 1, 2, 2, 0, 4, 0, 3, 1],
[0, 1, 2, 1, 3, 2, 2, 2, 4, 4],
[3, 3, 2, 1, 3, 3, 1, 2, 0, 1],
[1, 2, 1, 2, 1, 3, 3, 4, 0, 5],
[1, 0, 1, 3, 2, 1, 3, 2, 0, 3],
[1, 2, 2, 2, 1, 1, 2, 2, 1, 3]])


## 16.8.5. Poisson¶

Let us now perform a thought experiment. Let us say we are standing at a bus stop and we want to know how many buses will arrive in the next minute. Lets start by considering $$X^{(1)} \sim \mathrm{Bernoulli}(p)$$ Which is simply the probability that a bus arrives in the one minute window. For bus stops far from an urban center, this might be a pretty good approximation since we will never see more than one bus at a time.

However, if we are in a busy area, it is possible or even likely that two buses will arrive. We can model this by splitting our random variable into two parts for the first 30 seconds, or the second 30 seconds. In this case we can write

(16.8.11)$X^{(2)} \sim X^{(2)}_1 + X^{(2)}_2.$

where $$X^{(2)}$$ is the total sum, and $$X^{(2)}_i \sim \mathrm{Bernoulli}(p/2)$$. The total distribution is then $$X^{(2)} \sim \mathrm{Binomial}(2,p/2)$$.

Why stop here? Let us continue to split that minute into $$n$$ parts. By the same reasoning as above, we see that

(16.8.12)$X^{(n)} \sim \mathrm{Binomial}(n,p/n).$

Let us consider these random variables. By the previous section, we know that this has mean $$\mu_{X^{(n)}} = n(p/n) = p$$, and variance $$\sigma_{X^{(n)}}^2 = n(p/n)(1-(p/n)) = p(1-p/n)$$. If we take $$n \rightarrow \infty$$, we can see that these numbers stabilize to $$\mu_{X^{(\infty)}} = p$$, and variance $$\sigma_{X^{(\infty)}}^2 = p$$! What this indicates is that there could be some random variable we can define which is well defined in this infinite subdivision limit.

This should not come as too much of a surprise, since in the real world we can just count the number of bus arrivals, however it is nice to see that our mathematical model is well defined. This result is known as the law of rare events.

Following through this reasoning carefully, we can arrive at the following model. We will say that $$X \sim \mathrm{Poisson}(\lambda)$$ if it is a random variable which takes the values $$\{0,1,2,\ldots\}$$ with probability

(16.8.13)$p_k = \frac{\lambda^ke^{-\lambda}}{k!}.$

The value $$\lambda > 0$$ is known as the rate, and denotes the average number of arrivals we expect in one unit of time (note that we above restricted our rate to be less than zero, but that was only to simplify the explanation).

We may sum this probability mass function to get the cumulative distribution function.

(16.8.14)$\begin{split}F(x) = \begin{cases} 0 & x < 0, \\ e^{-\lambda}\sum_{m = 0}^k \frac{\lambda^m}{m!} & k \le x < k+1 \text{ with } 0 \le k. \end{cases}\end{split}$

Let us first plot the probabilty mass function.

lam = 5.0

xs = [i for i in range(20)]
pmf = np.array([np.exp(-lam) * lam**k / factorial(k) for k in xs])

d2l.plt.stem(xs, pmf, use_line_collection=True)
d2l.plt.xlabel('x')
d2l.plt.ylabel('p.m.f.')
d2l.plt.show() Now, let us plot the cumulative distribution function.

x = np.arange(-1, 21, 0.01)
cmf = np.cumsum(pmf)
F = lambda x: 0 if x < 0 else 1 if x > n else cmf[int(x)]

d2l.plot(x, np.array([F(y) for y in x.tolist()]), 'x', 'c.d.f.') As we saw above, the means and variances are particularly concise. If $$X \sim \mathrm{Poisson}(\lambda)$$, then:

• $$\mu_X = \lambda$$,

• $$\sigma_X^2 = \lambda$$.

This can be sampled as follows.

np.random.poisson(lam, size=(10, 10))

array([[ 8,  6,  6,  4,  3,  4,  6,  8,  5,  6],
[ 3,  3,  4,  2,  3,  5,  5,  8,  7,  6],
[ 2,  7,  4,  6,  6,  7,  9,  6,  3,  3],
[ 6,  7,  8,  4,  7,  2,  2,  6,  1,  4],
[ 4,  7,  2,  2,  5,  7,  6,  5, 10,  5],
[ 6,  3,  3,  5,  2,  6, 11,  1,  6,  7],
[ 6,  6,  5,  7,  5,  6,  3,  3,  8,  8],
[ 5,  3,  5,  6,  5,  3,  3,  9,  3,  4],
[ 5,  7, 10,  4,  4,  2,  3,  6,  7,  5],
[ 7,  5,  7,  6,  5,  1,  2,  4,  3,  8]])


## 16.8.6. Gaussian¶

Now Let us try a different, but related experiment. Let us say we again are performing $$n$$ independent $$\mathrm{Bernoulli}(p)$$ measurements $$X_i$$. The distribution of the sum of these is $$X^{(n)} \sim \mathrm{Binomial}(n,p)$$. Rather than taking a limit as $$n$$ increases and $$p$$ decreases, Let us fix $$p$$, and then send $$n \rightarrow \infty$$. In this case $$\mu_{X^{(n)}} = np \rightarrow \infty$$ and $$\sigma_{X^{(n)}}^2 = np(1-p) \rightarrow \infty$$, so there is no reason to think this limit should be well defined.

However, not all hope is lost! Let us just make the mean and variance be well behaved by defining

(16.8.15)$Y^{(n)} = \frac{X^{(n)} - \mu_{X^{(n)}}}{\sigma_{X^{(n)}}}.$

This can be seen to have mean zero and variance one, and so it is plausible to believe that it will converge to some limiting distribution.

p = 0.2
ns = [1, 10, 100, 1000]
d2l.plt.figure(figsize=(10, 3))
for i in range(4) :
n = ns[i]
pmf = np.array([p**i * (1-p)**(n-i) * binom(n, i) for i in range(n + 1)])
d2l.plt.subplot(1, 4, i + 1)
d2l.plt.stem([(i - n*p)/np.sqrt(n*p*(1 - p)) for i in range(n + 1)], pmf,
use_line_collection=True)
d2l.plt.xlim([-4, 4])
d2l.plt.xlabel('x')
d2l.plt.ylabel('p.m.f.')
d2l.plt.title("n = {}".format(n))
d2l.plt.show() One thing to note: compared to the Poisson case, we are now diving by the standard deviation which means that we are squeezing the possible outcomes into smaller and smaller areas. This is an indication that our limit will no longer be discrete, but rather a continuous distribution.

A derivation of what occurs is well beyond the scope of this document, but the central limit theorem states that as $$n \rightarrow \infty$$, this will yield the Gaussian Distribution (or sometimes Normal distribution). More explicitly, for any $$a,b$$:

(16.8.16)$\lim_{n \rightarrow \infty} P(Y^{(n)} \in [a,b]) = P(\mathcal{N}(0,1) \in [a,b]),$

where we say a random variable is normally distributed with given mean $$\mu$$ and variance $$\sigma^2$$, written $$X \sim \mathcal{N}(\mu,\sigma^2)$$ if $$X$$ has density

(16.8.17)$p_X(x) = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{(x-\mu)^2}{2\sigma^2}}.$

Let us first plot the probability density function.

mu = 0; sigma = 1

x = np.arange(-3, 3, 0.01)
p = 1 / np.sqrt(2 * np.pi * sigma**2) * np.exp(-(x - mu)**2 / (2 * sigma**2))

d2l.plot(x, p, 'x', 'p.d.f.') Now, let us plot the cumulative distribution function.

def phi(x):
return (1.0 + erf((x - mu) / (sigma * np.sqrt(2)))) / 2.0

d2l.plot(x, np.array([phi(y) for y in x.tolist()]), 'x', 'c.d.f.') Keen-eyed readers will recognize some of these terms. Indeed, we encountered this integral we encountered in Section 16.5. Indeed we need exactly that computation to see that this $$p_X(x)$$ has total area one and is thus a valid density.

Our choice of working with coin flips made computations shorter, but nothing about that choice was fundamental. Indeed, if we take any collection of independent identically distributed random variables $$X_i$$, and form

(16.8.18)$X^{(N)} = \sum_{i=1}^N X_i.$

then

(16.8.19)$\frac{X^{(N)} - \mu_{X^{(N)}}}{\sigma_{X^{(N)}}},$

will be approximately Gaussian.

This is the reason that the Gaussian is so central to probability, statistics, and machine learning. Whenever we can say that something we measured is a sum of many small independent contributions, we can safely assume that the thing being measured will be close to Gaussian.

There are many more fascinating properties of Gaussians than we can get into at this point. In particular, the Gaussian is what is known as a maximum entropy distribution. We will get into entropy more deeply in Section 16.11, however all we need to know at this point is that it is a measure of randomness. In a rigorous mathematical sense, we can think of the Gaussian as the most random choice of random variable with fixed mean and variance. Thus, if we know that our random variable has some mean and variance, the Gaussian is in a sense the most conservative choice of distribution we can make.

To close the section, Let us recall that if $$X \sim \mathcal{N}(\mu,\sigma^2)$$, then:

• $$\mu_X = \mu$$,

• $$\sigma_X^2 = \sigma^2$$.

We can sample from the Gaussian (or normal) as shown below.

np.random.normal(mu, sigma, size=(10, 10))

array([[-1.04883453,  1.99713339, -0.17245203, -0.77078552,  1.5669609 ,
-1.00079803,  0.33799476, -2.12561343, -1.29440599, -0.95701883],
[ 0.12783447,  0.18120036,  1.8743029 , -0.78009534, -0.06358307,
-0.94137759, -0.5893523 , -0.58830864, -2.73688688, -1.07817684],
[-0.4129788 , -0.07174383,  0.41423889,  1.49778924, -1.48863642,
0.49999226,  1.33907339,  0.35494098,  1.23655945, -0.8098314 ],
[-0.54092773,  0.29345958,  1.58641094,  1.45543101,  0.38843555,
-2.27823182, -0.57397205, -1.34373465, -1.57065532, -0.28093902],
[ 1.31192687,  0.72844953, -0.24974771,  0.00726044,  0.02537142,
-0.06178455, -0.02734276, -1.47112918, -0.63595471,  1.36091162],
[-2.2836408 , -0.29064776, -1.85607859,  0.72140302, -1.55988144,
-0.26955426, -0.73851607, -1.35397422,  1.07783342,  0.78141596],
[-1.33214416,  0.97064713, -0.3337505 , -1.09735993, -0.99878837,
0.47622934, -1.06541807, -1.03610565,  1.55951125, -2.2136247 ],
[ 0.5519943 ,  0.72446498,  1.7072299 ,  0.64640045, -1.37111427,
-0.52697155, -1.65955206,  0.82730395,  0.6660435 ,  0.95897816],
[ 2.0446095 , -0.03596171, -2.11955621, -1.90196606, -1.56178734,
0.08282825,  0.54516254,  0.45916109,  0.17302571, -0.6298943 ],
[-0.873815  , -0.57184926, -1.13034752,  0.01794838,  1.56600009,
1.98312058, -0.72160458, -0.16692888, -0.09635971, -1.32565599]])


## 16.8.7. Summary¶

• Bernoulli random variables can be used to model events with a yes/no outcome.

• Discrete uniform distributions model selections from a finite set of possibilites.

• Continuous uniform distributions select from an interval.

• Binomial distributions model a series of Bernoulli random variables, and count the number of successes.

• Poisson random variables model the arrival of rare events.

• Gaussian random variables model the results of adding a large number of independent random variables together.

## 16.8.8. Exercises¶

1. What is the standard deviation of a random variable that is the difference $$X-Y$$ of two indepent binomial random variables $$X,Y \sim \mathrm{Binomial}(16,1/2)$$.

2. If we take a Poisson random variable $$X \sim \mathrm{Poisson}(\lambda)$$ and consider $$(X - \lambda)/\sqrt{\lambda}$$ as $$\lambda \rightarrow \infty$$, we can show that this becomes approximately Gaussian. Why does this make sense?

3. What is the probability mass function for a sum of two discrete uniform random variables on $$n$$ elements?