Introduction to Simulation Using Python
Introduction to Simulation Using Python
1
2 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
In this chapter, we will use the Numpy and Scipy libraries for mathematical functions and
Matplotlib’s Pyplot interface for plotting, though there are many good choices available. Many
Python distributions will include these modules by default. If yours does not, they can be
installed from your operating system command line (Command Prompt on Windows, Terminal
on MacOS, etc.) using pip. For example, to install Numpy, use
import numpy as np
import scipy as sp
import matplotlib . pyplot as plt
rng . random ()
which returns a pseudorandom value drawn from the standard uniform distribution on the
half-open interval [0, 1). Also,
rng . random ( n )
returns a list of n independent pseudorandom values drawn from the standard uniform distri-
bution on the half-open interval [0, 1), while
rng . random ([ m , n ])
returns an m × n matrix.
14.3. DISCRETE AND CONTINUOUS RANDOM NUMBER GENERATORS 3
P (H) = P (X = 1)
= P (U < p)
=p
Therefore, X has Bernoulli(p) distribution. The Python code for Bernoulli(p) is:
def bernoulli ( p ):
U = rng . random ()
return ( U < p )
Since the “random” command returns a number between 0 and 1, we divided the interval [0, 1]
into two parts, p and 1 − p in length. Then, the value of X is determined based on where the
number generated from the uniform distribution fell.
Example 2. (Coin Toss Simulation) Write code to simulate tossing a fair coin to see how the
law of large numbers works.
Solution: You can write:
n = 1000
U = rng . random ( n )
toss = ( U < 0.5)
avg = [ sum ( toss [: i ])/ i for i in range (1 , n +1)]
plt . xlabel ( " Coin Toss Number " )
plt . ylabel ( " Proportion of Heads " )
plt . axis ([0 , n ,0 ,1])
plt . plot ( range (1 , n +1) , avg )
plt . show ()
If you run the above code to compute the proportion of 1’s in the variable “toss,” the result will
look like Figure 14.1. You can also assume the coin is biased with probability of heads equal to
0.6 by replacing the third line of the previous code with:
Lemma 1. If X1 , X2 , ..., Xn are independent Bernoulli(p) random variables, then the random
variable X defined by X = X1 + X2 + ... + Xn has a Binomial(n, p) distribution.
To generate a random variable X ∼ Binomial(n, p), we can toss a coin n times and count the
number of heads. Counting the number of heads is exactly the same as finding X1 +X2 +...+Xn ,
where each Xi is equal to 1 if the corresponding coin toss results in heads and 0 otherwise.
Since we know how to generate Bernoulli random variables, we can generate a Binomial(n, p)
by adding n independent Bernoulli(p) random variables.
def binomial (n , p ):
U = rng . random ( n )
return sum ( U < p )
14.3. DISCRETE AND CONTINUOUS RANDOM NUMBER GENERATORS 5
j−1 j
!
X X
P (X = xj ) = P pk ≤ U < pk
k=0 k=0
= pj
p0 p1 p2 p3 ··· pj
0 1
Example 4. Give an algorithm to simulate the value of a random variable X such that
P (X = 1) = 0.35
P (X = 2) = 0.15
P (X = 3) = 0.4
P (X = 4) = 0.1
A0 = [0, 0.35)
A1 = [0.35, 0.5)
A2 = [0.5, 0.9)
A3 = [0.9, 1)
6 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
P (X = xi ) = P (U ∈ Ai )
= pi
def X ():
A = [0.35 ,0.5 ,0.9 ,1]
x = [1 ,2 ,3 ,4]
j = 0
U = rng . random ()
while U > A [ j ]:
j = j + 1
return x [ j ]
The same result can be achevied using the Numpy choice function:
Theorem 1. Let U ∼ U nif orm(0, 1) and F be a CDF which is strictly increasing. Also,
consider a random variable X defined as
X = F −1 (U ).
Then,
X∼F (The CDF of X is F ).
Proof:
P (X ≤ x) = P (F −1 (U ) ≤ x)
= P (U ≤ F (x)) (increasing function)
= F (x)
Now, let’s see some examples. Note that to generate any continuous random variable X with
the continuous CDF F , F −1 (U ) has to be computed.
14.3. DISCRETE AND CONTINUOUS RANDOM NUMBER GENERATORS 7
(1 − U ) ∼ U nif orm(0, 1)
U 1−U
0 1
Example 7. (Poisson) Generate a Poisson random variable. Hint: In this example, use the fact
that the number of events in the interval [0, t] has Poisson distribution when the elapsed times
between the events are Exponential.
Solution: We want to employ the definition of Poisson processes. Assume N represents the
number of events (arrivals) in [0,t]. If the interarrival times are distributed exponentially (with
parameter λ) and independently, then the number of arrivals occurred in [0,t], N , has Poisson
distribution with parameter λt (Figure 14.4). Therefore, to solve this problem, we can repeat
generating Exponential(λ) random variables while their sum is not larger than 1 (choosing
t = 1). More specifically, we generate Exponential(λ) random variables
−1
Ti = ln(Ui )
λ
by first generating uniform random variables Ui ’s. Then we define
X = max {j : T1 + · · · + Tj ≤ 1}
To finish this section, let’s see how to convert uniform numbers to normal random variables.
The normal distribution is extremely important in science because it is very commonly occuring.
Theorem 3. (Box-Muller transformation) We can generate a pair of independent normal vari-
ables (Z1 , Z2 ) by transforming a pair of independent U nif orm(0, 1) random variables (U1 , U2 )
[1].
14.3. DISCRETE AND CONTINUOUS RANDOM NUMBER GENERATORS 9
√
Z1 = √−2 ln U1 cos(2πU2 )
Z2 = −2 ln U1 sin(2πU2 )
Example 8. (Box-Muller) Generate 5000 pairs of normal random variables and plot both
histograms.
Solution:
Figure 14.5: Histogram of a pair of normal random variables generated by Box-Muller transfor-
mation
10 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
rng . binomial (n ,p ,[ a , b ])
Even more functionality is available in Scipy’s stats module. In addition to random sampling
of various distributions, Scipy can also compute of the corresponding PMFs/PDFs, CDFs, and
more. The above Numpy command is equivalent to the Scipy command
and similarly for the CDF. See the Scipy documentation for details [3].
Table 14.1: Discrete distributions. Scipy name can be followed by .rvs(...) for a random sample,
.pmf(k,...) for the PMF at k, or .cdf(k,...) for the CDF at k.
Table 14.2: Continuous distributions. PMFs are replaced by PDFs, given by .pdf(x,...). Note
that in both libraries, the paramater to the exponential distribution is the scale 1/λ, not the
rate λ itself.
14.5. EXERCISES 11
14.5 Exercises
1. Write Python programs to generate Geometric(p) and Negative Binomial(i,p) random
variables from a uniform random sample (i.e., without using the library functions from
Section 14.4).
Solution: To generate a Geometric random variable, we run a loop of Bernoulli trials until
the first success occurs. K counts the number of failures plus one success, which is equal
to the total number of trials.
def geometric ( p ):
K = 1
while ( rng . random () > p ):
K = K + 1
return K
Now, we can generate Geometric random variable i times to obtain a Negative Binomial(i, p)
variable as a sum of i independent Geometric (p) random variables.
def negativebinomial (i , p ):
return sum ([ geometric ( p ) for j in range ( i )])
2. (Poisson) Use the algorithm for generating discrete random variables to obtain a Poisson
random variable with parameter λ = 2.
Solution: We know a Poisson random variable takes all nonnegative integer values with
probabilities
λi
pi = P (X = xi ) = e−λ for i = 0, 1, 2, · · ·
i!
To generate a P oisson(λ), first we generate a random number U . Next, we divide the
interval [0, 1] into subintervals such that the jth subinterval has length pj (Figure 14.2).
Assume
x0 if (U < p0 )
x1 if (p0 ≤ U < p0 + p1 )
.
..
X= P
j−1 Pj
xj if p ≤ U < p
k=0 k k=0 k
.
.
.
Here xi = i − 1, so
if your random number generator produces a Standard Uniform random variable U . Hint:
use the inverse transformation method.
Solution:
5
FX (X) = X 2 = U (0 < x < 1)
2
X=U 5
def X ():
U = rng . random ()
return U **(2/5)
def X ():
U = rng . random ()
return np . sqrt (2* U + 1/4) - 1/2
6. (The Rejection Method) When we use the Inverse Transformation Method, we need a
simple form of the cdf F (x) that allows direct computation of X = F −1 (U ). When
F (x) doesn’t have a simple form but the pdf f (x) is available, random variables with
density f (x) can be generated by the rejection method. Suppose you have a method
for generating a random variable having density function g(x). Now, assume you want to
generate a random variable having density function f (x). Let c be a constant such that
f (y)
≤ c (for all y)
g(y)
Show that the following method generates a random variable with density function f (x).
14 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
Figure 14.6: Simulation of a Cauchy distribution shows that the mean is not defined.
f (Y )
- If U ≤ cg(Y ) , set X = Y . Otherwise, return to step 1.
Solution: The number of times N that the first two steps of the algorithm need to be called
is itself a random variable and has a geometric distribution with “success” probability
f (Y )
p=P U≤
cg(Y )
14.5. EXERCISES 15
7. Use the rejection method to generate a random variable having density function Beta(2, 4).
Hint: Assume g(x) = 1 for 0 < x < 1.
Solution:
f (x) = 20x(1 − x)3 0<x<1
g(x) = 1 0 < x < 1
f (x)
= 20x(1 − x)3
g(x)
16 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
We need to find the smallest constant c such that f (x)/g(x) ≤ c. Differentiation of this
quantity yields
d fg(x)
(x)
=0
dx
1
Thus, x =
4
f (x) 135
Therefore, ≤
g(x) 64
f (x) 256
Hence, = x(1 − x)3
cg(x) 27
def X ():
Y = rng . random ()
U = rng . random ()
while U > 256/27* Y *(1 - Y )**3:
Y = rng . random ()
U = rng . random ()
return Y
5
8. Use the rejection method to generate a random variable having the Gamma( 2 , 1) density
function. Hint: Assume g(x) is the pdf of the Gamma α = 25 , λ = 1 .
Solution:
4 3
f (x) = √ x 2 e−x , x > 0
3 π
2 2x
g(x) = e− 5 x > 0
5
f (x) 10 3 3x
= √ x 2 e− 5
g(x) 3 π
f (x)
d g(x)
=0
dx
5
Hence, x=
2
3
10 5 2 −3
c= √ e2
3 π 2
3 −3x
f (x) x2 e 5
= 3 −3
cg(x) 5 2
e2
2
3 −3Y
Y 2e 5
- If U2 < 3 −3 , set X = Y . Otherwise, execute the step 1.
5 2
( )
2
e 2
9. Use the rejection method to generate a standard normal random variable. Hint: Assume
g(x) is the pdf of the exponential distribution with λ = 1.
Solution:
2 x2
f (x) = √ e− 2 0 < x < ∞
2π
g(x) = e−x 0 < x < ∞ (Exponential density function with mean 1)
r
f (x) 2 x− x2
Thus, = e 2
g(x) π
f (x)
Thus, x = 1 maximizes
g(x)
r
2e
Thus, c =
π
2
f (x) (x−1)
= e− 2
cg(x)
10. Use the rejection method to generate a Gamma(2, 1) random variable conditional on its
value being greater than 5, that is
xe−x
f (x) = R ∞ −x
5 xe dx
xe−x
= (x ≥ 5)
6e−5
Hint: Assume g(x) be the density function of exponential distribution.
Solution: Since a Gamma(2, 1) random variable has expected value 2, we use an exponen-
tial distribution with mean 2 that is conditioned to be greater than 5.
xe(−x)
f (x) = R ∞ (−x)
5 xe dx
xe(−x)
= x≥5
6e(−5)
1 (− x2 )
e
g(x) = 2 −5 x≥5
e2
f (x) x x−5
= e−( 2 )
g(x) 3
18 CHAPTER 14. INTRODUCTION TO SIMULATION USING PYTHON
f (x)
We obtain the maximum in x = 5 since g(x) is decreasing. Therefore,
f (5) 5
c= =
g(5) 3
[1] http://projecteuclid.org/download/pdf_1/euclid.aoms/1177706645
[2] https://numpy.org/doc/stable/reference/random/generator.html#distributions
[3] https://docs.scipy.org/doc/scipy/reference/stats.html#
probability-distributions
[4] Michael Baron, Probability and Statistics for Computer Scientists. CRC Press, 2006
19