Generation of Continuous Random Variables
Subjects: Stochastic Simulation
Links: Pseudo-random number generator, Continuous Distributions
Since we can generate a random number
Method of the Inverse Transform
Let
The main problem with this method is that finding an inverse can be really complicated, or there can be cases where there is no inverse.
The inverse transform sampling method works as follows:
- Generate a random number
from the standard uniform distribution in the interval , i.e. from . - Find the generalised inverse of the desired cdf, i.e.
- Compute
. The computed random variable has distribution and thereby the same law as .
import micropip
await micropip.install('numpy')
import numpy as np
def inverse_transform_sampling(inverse_cdf):
u = np.random.uniform()
return inverse_cdf(u)
mean = 2
inverse_exponential_cdf = lambda p: -np.log(1-p)*mean
sampling = lambda : inverse_transform_sampling(inverse_exponential_cdf)
print(sampling())
Method of Rejection Sampling
The rejection sampling method generates sampling values from a target distribution
The algorithm is as follows: Let
- Obtain a sample
from the distribution and a sample from , - Check if
. - If this holds, accept
as sample drawn from . - If not, reject the value of
and return to the sampling step.
- If this holds, accept
def rejection_sampling(goal_pdf, M, auxiliary_pdf, auxiliary_sample):
while True:
u = np.random.uniform()
y = auxiliary_sample()
if u < goal_pdf/(M*auxiliary_pdf):
return y
Ratio of Uniforms
Given that is easy to generate uniform random variables, the idea of the method of uniform ratios is to transform two variables
Th: Let
From this theorem we get the following algorithm:
- We generate
and . - Check if
- if it is true, then accept the value
. - If not, then go back to the generation step.
- if it is true, then accept the value
This is particularly useful for generating a target density that is only known up to a normalising constant, i.e.
The following result may be useful:
Th: Suppose
This helps us get the most efficient
def uniform_ratio(bounding_function, a_bound, b_bound, c_bound):
while True:
u1, u2 = np.random.uniform(size = 2)
u = a_bound * u
v = b_bound + v *(c_bound - b_bound)
if u*u <= bounding_function(v/u):
return v/u
Box-Muller Method
The Box-Muller method transforms two
The main idea of the Box-Muller method is actually if we can transform two normally distributed random variables, into uniform random variables. Let
\begin{align*}
X_1 = \sqrt{-2\ln (U_1)} \cos(2\pi U_2) \
X_2 = \sqrt{-2\ln (U_1)} \cos(2\pi U_2)
\end{align*}$$
So the method is that given two
Z_1 = \sqrt{-2\ln (U_1)} \cos(2\pi U_2) \
Z_2 = \sqrt{-2\ln (U_1)} \cos(2\pi U_2)
\end{align*}$$where
from math import pi
def box_muller_transform():
u1, u2 = np.random.uniform(size = 2)
return (np.sqrt(-2 * np.log(u1))*np.cos(2*pi * u2), np.sqrt(-2 * np.log(u1))*np.sin(2*pi * u2))
print(box_muller_transform())