# 8 Discrete Probability Distributions¶

## 8.2 Binomial Distribution¶

The following code plots the probability mass function (PMF) of $B_{p,n}$, the binomial distribution with parameters $p$ and $n$. It contains interactive sliders that you can use to vary $n$ over the interval $[0,30]$ and $p$ over the interval $[0, 1]$.

In [1]:
%matplotlib inline


Let us now load the required code and analyze it part by part.

In [2]:
# %load plot_pmf.py
import numpy as np
import matplotlib.pyplot as plt

from scipy import stats
import ipywidgets as widgets

def plot_pmf(n, p):
'''
Plot the probability mass function of Binom(n, p)
'''
k = np.arange(0, n + 1)
P_binom = stats.binom.pmf(k, n, p)
plt.plot(k, P_binom, '-o')
axes = plt.gca()
axes.set_xlim([0, n])
axes.set_ylim([0, 1.1 * max(P_binom)])
plt.title('PMF of Bin(%i, %.2f)' % (n, p))
plt.xlabel('Number k of successes')
plt.ylabel('Probability of k successes')
plt.show()

widgets.interact(
plot_pmf,
n=widgets.IntSlider(min=0, max=30, step=1, value=15),
p=widgets.FloatSlider(min=0, max=1, step=0.01, value=0.5))

Out[2]:
<function __main__.plot_pmf>

First, import the necessary function libraries. Numerical functions from numpy, plotting functions from matplotlib.pyplot, the statistical function binom from scipy.stats, and an interactive slider from ipywidgets to vary $n$ and $p$ in real time.

In [3]:
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import binom
import ipywidgets as widgets


Next define a function plot_pmf that takes arguments $n$ and $p$ and plots the PMF.

In [4]:
def plot_pmf(n, p):
'''
Plot the probability mass function of Binom(n, p).
'''
k = np.arange(0, n + 1)
P_binom = binom.pmf(k, n, p)
plt.plot(k, P_binom, '-o')

'''
The snippet below sets the axes limits and
associated properties of the plot.
'''
axes = plt.gca()
axes.set_xlim([0, n])
axes.set_ylim([0, 1.1 * max(P_binom)])
plt.title('PMF of Bin(%i, %.2f)' % (n, p))
plt.xlabel('Number k of successes ')
plt.ylabel('Probability of k succcesses')
plt.show()


Finally, define an interactive slider that enables you to vary $n$ over $[0,30]$ and $p$ over $[0,1]$ and then plot the resulting PMF according to the updated values of both the parameters.

In [5]:
widgets.interact(
plot_pmf,
n=widgets.IntSlider(min=0, max=30, step=1, value=15),
p=widgets.FloatSlider(min=0, max=1, step=0.01, value=0.5))

Out[5]:
<function __main__.plot_pmf>

## 8.3 Poisson Distribution¶

### PMF¶

We follow the same procedure to plot the Poisson PMF.

In [6]:
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import poisson
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
def f(n, λ):
k = np.arange(0, n+1)
P_poisson = poisson.pmf(k, λ)
plt.plot(k, P_poisson, '-o')
plt.title('PMF of Poisson(%i)' %λ)
plt.xlabel('Number of Events')
plt.ylabel('Probability of Number of Events')
plt.show()
interact(f, n=widgets.IntSlider(min=0, max=50, step=1, value=25), λ=widgets.FloatSlider(min=0, max=30, step=0.1, value=5))

Out[6]:
<function __main__.f>

### Poisson Approximation of the Binomial Distribution¶

Observe how well Poisson$(np)$ approximates Binomial$(n, p)$ for small values of $p$.

In [7]:
from __future__ import print_function
from IPython.display import display
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import binom, poisson
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import warnings
warnings.filterwarnings("ignore")
e = np.e
def f(n, p, α):
k = np.arange(0, n+1)
x = np.linspace(0, n+1, 1000)
λ = n*p
stddev = λ**0.5
P_poisson = poisson.pmf(k, λ)
P_binom = binom.pmf(k, n, p)
plt.plot(k, P_poisson, 'r', label = "Poisson(%0.2f)" %λ)
#plt.title('PMF of Poisson(%i)' %λ)
#plt.xlabel('Number of Events')
#plt.ylabel('Probability of Number of Events')
P_binom_shifted = P_binom
fig = plt.gcf()
fig.set_size_inches(20,10)
plt.plot(k, P_binom, 'b-', label = "Bin(%i, %0.2f)" %(n,p))
axes = plt.gca()
axes.set_xlim([max(0,(1-e**α)*λ),min((1+e**α)*λ,n)])
if n<10:
axes.set_xlim([0,n])
axes.set_ylim([0,1.02*max(max(P_binom_shifted),max(P_poisson))])
w = e**α
plt.title('Poisson Approximation of Binomial, |x - μ| < %0.1fσ' %(w), fontsize = 20)
plt.xlabel('n', fontsize = 20)
plt.ylabel('y', fontsize = 20)
plt.legend(fontsize = 20)
plt.xticks(fontsize = 16)
plt.yticks(fontsize = 16)
print('       %0.3f' %e**α)
plt.show()
print("")
print('|| P_Poisson - P_Binomial ||\u2081 = ',sum(abs(P_poisson-P_binom)))
print("")
print("")
#return e**α
interact(f, n=widgets.IntSlider(min=2, max=2000, step=1, value=15), p=widgets.FloatSlider(min=0.01, max=0.3, step=0.01, value=0.1), α = widgets.FloatSlider(description = 'Range', min=0,max=5,step=0.01, value = 3, readout = False))

       20.086

|| P_Poisson - P_Binomial ||₁ =  0.0546517048417


Out[7]:
<function __main__.f>

## 8.4 Geometric Distribution¶

### PMF and CDF¶

In [8]:
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import binom
from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets
import warnings
warnings.filterwarnings("ignore")

def f(p, n_max, CDF):
x = np.arange(1, n_max + 1)
y = [((1 - p)**(z - 1)) * p for z in x]
z = [(1 - (1 - p)**zz) for zz in x]
plt.plot(x, y, 'o-', label='PDF')
if CDF == True:
plt.plot(x, z, 'ro-', label='CDF')
#plt.title("Exponential(%.2f)" %λ, fontsize = 20)
plt.gcf().set_size_inches(20, 10)
axes = plt.gca().set_xlim([1, n_max])
if n_max == 1:
axes = plt.gca().set_xlim([0, 1])
plt.plot([0, 1], [p, p], 'b')
plt.xticks([1])
plt.xlabel('n', fontsize=20)
plt.ylabel('y', fontsize=20)
plt.title('PMF of Geometric(%0.2f)' % p, fontsize=20)
plt.xticks(fontsize=16)
plt.yticks(fontsize=16)
plt.legend(fontsize=18)
plt.show()

interact(
f,
p=widgets.FloatSlider(min=0, max=1, step=0.01, value=0.5),
n_max=widgets.IntSlider(min=1, max=1000, step=1, value=10),
CDF=widgets.ToggleButton(False))

Out[8]:
<function __main__.f>