Generate Random Variable Using Inverse Transform Method in Python | by Raden Aurelius Andhika Viadinugroho | Towards Data Science

Motivation
In simulation theory, generating random variables become one of the most important “building block”, where these random variables are mostly generated from Uniform distributed random variable. One of the methods that can be used to generate the random variables is the Inverse Transform method. In this article, I will show you how to generate random variables (both discrete and continuous case) using the Inverse Transform method in Python.
The Concept
Given random variable U where U is uniformly distributed in (0,1). Suppose that we want to generate random variable X where the Cumulative Distribution Function (CDF) is
The idea of the inverse transform method is to generate a random number from any probability distribution by using its inverse CDF as follows.
For discrete random variables, the steps are slightly different. Suppose that we want to generate the value of a discrete random variable X that has a Probability Mass Function (PMF)
To generate the value of X, generate a random variable U where U is uniformly distributed in (0,1) and set
From the steps above, we can create the inverse transform method’s algorithm as follows.
Implementation : Continuous r.v. case
First, we implement this method for generating continuous random variables. Suppose that we want to simulate a random variable X that follows the exponential distribution with mean λ (i.e. X~EXP(λ)). We know that the Probability Distribution Function (PDF) of the exponential distribution is
with the CDF as follows.
Then, we can write the inverse CDF as follows.
In Python, we can simply implement it by writing these lines of code as follows.
### Generate exponential distributed random variables given the mean ### and number of random variablesdef exponential_inverse_trans(n=1,mean=1):    U=uniform.rvs(size=n)    X=-mean*np.log(1-U)    actual=expon.rvs(size=n,scale=mean)        plt.figure(figsize=(12,9))    plt.hist(X, bins=50, alpha=0.5, label="Generated r.v.")    plt.hist(actual, bins=50, alpha=0.5, label="Actual r.v.")    plt.title("Generated vs Actual %i Exponential Random Variables" %n)    plt.legend()    plt.show()    return X
We can try the code above by running some examples below. Note that the result might be different since we want to generate random variables.
cont_example1=exponential_inverse_trans(n=100,mean=4)cont_example2=exponential_inverse_trans(n=500,mean=4)cont_example3=exponential_inverse_trans(n=1000,mean=4)
Looks interesting. We can see that the generated random variable having a pretty similar result if we compare it with the actual one. You can adjust the mean (Please note that the mean that I define for expon.rvs() function is a scale parameter in exponential distribution) and/or the number of generated random variables to see different results.
Implementation : Discrete r.v. case
For discrete random variable case, suppose that we want to simulate a discrete random variable case X that follows the following distribution
First, we write the function to generate the discrete random variable for one sample with these lines of code.
### Generate arbitary discrete distributed random variables given ### the probability vectordef discrete_inverse_trans(prob_vec):    U=uniform.rvs(size=1)    if U<=prob_vec[0]:        return 1    else:        for i in range(1,len(prob_vec)+1):            if sum(prob_vec[0:i])<U and sum(prob_vec[0:i+1])>U:                return i+1
Then, we create a function to generate many random variable samples with these lines of code.
def discrete_samples(prob_vec,n=1):    sample=[]    for i in range(0,n):        sample.append(discrete_inverse_trans(prob_vec))    return np.array(sample)
Finally, we create a function to simulate the result and compare it with the actual one by these lines of code.
def discrete_simulate(prob_vec,numbers,n=1):    sample_disc=discrete_samples(prob_vec,n)    unique, counts=np.unique(sample_disc,return_counts=True)        fig=plt.figure()    ax=fig.add_axes([0,0,1,1])    prob=counts/n    ax.bar(numbers,prob)    ax.set_title("Simulation of Generating %i Discrete Random Variables" %n)    plt.show()        data={'X':unique,'Number of samples':counts,'Empirical Probability':prob,'Actual Probability':prob_vec}    df=pd.DataFrame(data=data)    return df
We can run some examples below to see the results. Again, note that the result might be different since we want to generate random variables.
prob_vec=np.array([0.1,0.3,0.5,0.05,0.05])numbers=np.array([1,2,3,4,5])dis_example1=discrete_simulate(prob_vec, numbers, n=100)dis_example2=discrete_simulate(prob_vec, numbers, n=500)dis_example3=discrete_simulate(prob_vec, numbers, n=1000)
In[11]: dis_example1Out[11]:    X  Number of samples  Empirical Probability  Actual Probability0  1                  8                   0.08                0.101  2                 35                   0.35                0.302  3                 50                   0.50                0.503  4                  5                   0.05                0.054  5                  2                   0.02                0.05In[12]: dis_example2Out[12]:    X  Number of samples  Empirical Probability  Actual Probability0  1                 53                  0.106                0.101  2                159                  0.318                0.302  3                234                  0.468                0.503  4                 30                  0.060                0.054  5                 24                  0.048                0.05In[13]: dis_example3Out[13]:    X  Number of samples  Empirical Probability  Actual Probability0  1                108                  0.108                0.101  2                290                  0.290                0.302  3                491                  0.491                0.503  4                 51                  0.051                0.054  5                 60                  0.060                0.05
The result is interesting! We can see that the empirical probability is getting closer to the actual probability as we increase the number of random variable samples. Try to experiment with a different number of samples and/or different distribution to see different results.
Conclusion
And that’s it! This inverse transform method is a very important tool in statistics, especially in simulation theory where we want to generate random variables given random variables that are uniformly distributed in (0,1). The study case itself is pretty wide, you can use this method from generating Empirical CDF to predictive analytics.
See you in the next post!
Author Contact
LinkedIn : Raden Aurelius Andhika Viadinugroho
References
[1] Sheldon M. Ross, Simulation, 5th ed (2013), Elsevier
[2] Sheldon M. Ross, Introduction to Probability and Statistics for Engineers and Scientists, 5th ed (2014), Elsevier