# 16.8. Distributions¶

Now that we have learned how to work with probability in both the discrete and the continuous setting, let us get to know some of the common distributions encountered. Depending on the area of machine learning, we may 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 us 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 random variable encodes a coin flip which comes up $$1$$ with probability $$p$$ and $$0$$ with probability $$1-p$$. If we have a random variable $$X$$ 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 (16.8.2).

x = np.arange(-1, 2, 0.01)

def F(x):
return 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([[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 1, 1],
[0, 0, 0, 0, 1, 0, 0, 1, 0, 0],
[1, 0, 0, 0, 0, 1, 1, 0, 0, 0],
[1, 0, 1, 0, 1, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[0, 1, 1, 0, 0, 0, 0, 0, 0, 1]])


## 16.8.2. Discrete Uniform¶

The next commonly encountered random variable encountered is a discrete uniform. For our discussion here, we will assume that it is supported 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 a random variable $$X$$ with this distribution 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 probability 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 (16.8.4).

x = np.arange(-1, 6, 0.01)

def F(x):
return 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 sample an array of arbitrary shape from a discrete uniform random variable as follows.

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

/var/lib/jenkins/miniconda3/envs/d2l-en-numpy2-1/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([[2, 3, 1, 4, 3, 3, 3, 5, 5, 4],
[5, 2, 3, 2, 1, 1, 1, 1, 3, 2],
[4, 2, 4, 3, 3, 3, 1, 5, 2, 1],
[5, 2, 1, 1, 3, 4, 2, 1, 2, 2],
[5, 3, 4, 2, 2, 5, 5, 3, 1, 1],
[5, 5, 2, 2, 3, 2, 4, 3, 5, 3],
[2, 5, 4, 1, 4, 2, 1, 5, 3, 4],
[2, 5, 3, 5, 4, 5, 4, 5, 1, 1],
[5, 1, 5, 2, 4, 5, 3, 4, 1, 4],
[3, 5, 5, 4, 5, 4, 1, 4, 5, 5]])


## 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 discrete uniform 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 probability density function (16.8.6).

a, b = 1, 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 (16.8.7).

def F(x):
return 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 sample an array of arbitrary shape from a uniform random variable as follows. Note that it by default samples from a $$\mathrm{Uniform}([0,1])$$, so if we want a different range we need to scale it.

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

array([[2.2772497 , 2.10052906, 2.71975588, 1.6539631 , 1.2818714 ,
2.76947471, 1.6091751 , 2.93260382, 1.35883543, 2.07428942],
[1.66454625, 2.33943478, 2.47826145, 2.48498419, 1.52674596,
1.33210519, 1.0928671 , 1.97658207, 2.85161985, 2.09812445],
[1.29352369, 2.93477905, 1.6422046 , 2.51356403, 1.92877824,
1.18066778, 1.50755793, 2.28425661, 1.22993542, 1.84948527],
[1.27905668, 2.78777103, 2.28658016, 1.21471215, 2.27872216,
1.38305954, 2.47837839, 2.59714812, 1.11720789, 1.42021907],
[2.21186413, 2.16821664, 2.22592014, 2.76277514, 2.59787965,
1.53043981, 2.55077796, 2.65295581, 2.50485278, 1.64993912],
[2.62266459, 1.84272759, 1.20557088, 2.826701  , 1.33611616,
2.65803471, 1.29565242, 2.82651819, 2.82342575, 2.66678034],
[1.76308646, 1.82430605, 2.64306038, 1.87397992, 2.4979436 ,
1.38216188, 1.09715806, 2.87624747, 2.39169584, 2.74841178],
[2.8134004 , 1.07273948, 2.73301704, 1.40589726, 1.54764108,
2.62818365, 2.9204083 , 2.16231026, 1.20070729, 2.60672408],
[2.91319306, 2.26658791, 2.29201094, 1.64212651, 2.51917611,
2.33027698, 1.1779483 , 2.08419109, 2.45561679, 2.26508797],
[1.14274196, 1.46806407, 1.05256187, 1.59448651, 2.84946187,
2.85630859, 1.6116467 , 2.51278398, 1.16760419, 1.19688951]])


## 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 has 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 occurring. 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 probability mass function.

n, p = 10, 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 (16.8.10).

x = np.arange(-1, 11, 0.01)
cmf = np.cumsum(pmf)

def F(x):
return 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([[3, 1, 2, 3, 4, 0, 2, 1, 3, 3],
[1, 3, 2, 2, 3, 3, 1, 4, 0, 4],
[2, 1, 4, 2, 2, 2, 2, 1, 2, 1],
[1, 2, 2, 3, 1, 2, 1, 2, 3, 2],
[2, 3, 2, 5, 2, 1, 2, 2, 2, 1],
[0, 3, 2, 2, 2, 1, 2, 2, 1, 1],
[2, 3, 3, 0, 2, 3, 1, 0, 3, 1],
[2, 0, 4, 2, 1, 3, 1, 1, 2, 0],
[2, 0, 1, 0, 1, 1, 2, 3, 2, 4],
[3, 2, 2, 3, 0, 3, 0, 2, 2, 3]])


## 16.8.5. Poisson¶

Let us now perform a thought experiment. We are standing at a bus stop and we want to know how many buses will arrive in the next minute. Let us 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. We may never see more than one bus in a minute.

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).$

Consider these random variables. By the previous section, we know that (16.8.12) 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$$. This indicates that there could be some random variable we can define 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 discussion can be made formal 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.

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 probability mass function (16.8.13).

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 (16.8.14).

x = np.arange(-1, 21, 0.01)
cmf = np.cumsum(pmf)
def F(x):
return 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([[ 4,  8,  2,  5,  5,  7,  6,  3,  6,  6],
[ 2,  4,  7,  3,  2,  6,  4,  5,  6,  6],
[ 8,  6,  2,  5,  5,  4,  2,  4,  3,  4],
[ 5,  3,  4,  4, 10,  8,  5, 13,  8,  3],
[ 5,  4,  7,  3,  2,  3,  5,  7,  3,  7],
[ 3,  2,  4,  2,  7,  8,  2,  9,  7,  6],
[ 5, 11,  2,  6,  5,  6,  4,  4,  4,  5],
[ 4,  9,  5,  5,  2,  5,  4,  3,  7,  5],
[ 5,  6,  5,  2, 10,  3,  4,  5,  7,  6],
[ 9,  5,  6,  5,  6,  3,  4,  1,  7,  3]])


## 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. If we plot what these distributions look like, we will become even more convinced that it will work.

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 dividing 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.

A derivation of what occurs is 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 (16.8.17).

mu, sigma = 0, 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. It is beyond the scope of this appendix, but the Gaussian c.d.f. does not have a closed-form formula in terms of more elementary functions. We will use erf which provides a way to compute this integral numerically.

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 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. There are additional requirements needed to make it work, most commonly $$E[X^4] < \infty$$, but the philosophy is clear.

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

There are many more fascinating properties of Gaussians, and we would like to discuss one more here. 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([[ 0.83055323,  1.12322773, -1.8725062 , -1.22203964,  0.11685348,
0.49116292, -0.83584672,  1.00994946,  0.46548118,  0.20850084],
[-0.25214712, -2.0231409 ,  0.53201028,  0.41133647, -0.97425845,
-1.55820646, -0.25963784,  1.23996547, -0.65204654, -0.18682486],
[ 0.04738681,  0.83497196,  0.41062419, -0.05119946, -0.9959339 ,
-0.0989923 ,  1.2517953 , -1.15325827,  1.05126427, -0.17838408],
[ 0.68297602,  0.9525395 ,  0.17902886, -0.36486223, -0.34489577,
0.54261615,  0.76695548, -2.32653909, -0.23651059, -2.92173571],
[-0.62799686,  0.61656968, -1.65015214, -0.6393063 ,  0.53053409,
0.47888157,  0.69991277,  0.11571982, -0.73260097,  1.1793262 ],
[-1.00178168, -1.34808353, -1.46682361,  0.02934353, -0.33328947,
1.23392091, -0.53898421,  0.11912253,  0.91882323,  2.64962717],
[ 0.10044137, -0.05631001,  1.65253138,  0.10845836,  0.48925763,
0.84055913, -1.60844957, -0.96098762, -0.2689074 , -0.92675744],
[ 0.48439863, -1.66161049,  1.77270546, -0.57964928, -1.73532529,
0.75681467, -0.5623307 , -0.92062691,  0.25941407, -0.47488906],
[-0.86626228, -0.39008511,  0.09618277,  0.05520323, -0.18066296,
0.11086129, -0.17227446, -1.31375885, -0.53805372,  1.21346408],
[-0.34015482, -0.35295529,  1.09883984,  0.42853573,  1.95981165,
0.45058391,  0.01530127,  0.39858784, -0.66619994,  0.74415574]])


## 16.8.7. Summary¶

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

• Discrete uniform distributions model selects from a finite set of possibilities.

• 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 result 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 independent 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?

## 16.8.9. Discussions¶ 