Distributions with Two Random Variables#

Plotting the empirical PDF of \( \mathbf{z} \) (where \( \mathbf{z} = \mathbf{x} + \mathbf{y} \)) and compare it with the theoretical PDF derived from the convolution of the PDFs of \( \mathbf{x} \) and \( \mathbf{y} \).

Generate the Random Variables#

We’ll start by generating two independent random variables \( \mathbf{x} \) and \( \mathbf{y} \), each following a Gaussian distribution with zero mean and unit variance. Then we’ll compute \( \mathbf{z} = \mathbf{x} + \mathbf{y} \).

Plot the Empirical PDF of \( \mathbf{z} \)#

We’ll create a histogram of the data for \( \mathbf{z} \) and normalize it to represent the empirical PDF.

Calculate the Theoretical PDF of \( \mathbf{z} \)#

Since \( \mathbf{z} \) is the sum of two independent Gaussian random variables, its PDF can be calculated as the convolution of the individual PDFs of \( \mathbf{x} \) and \( \mathbf{y} \). Given that both \( \mathbf{x} \) and \( \mathbf{y} \) are Gaussian, the theoretical PDF of \( \mathbf{z} \) will also be Gaussian with mean \( 0 \) and variance \( 2 \) (since the variance of the sum is the sum of the variances).

import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from scipy.signal import convolve

def generate_joint_gaussian_pdf(num_samples):
    # Generate independent Gaussian random variables
    x = np.random.normal(0, 1, num_samples)
    y = np.random.normal(0, 1, num_samples)
    z = x + y

    # Define the grid for the histogram
    x_bins = np.linspace(-5, 5, 50)
    y_bins = np.linspace(-5, 5, 50)
    X, Y = np.meshgrid(x_bins, y_bins)

    # Compute the 2D histogram for the joint PDF
    hist, x_edges, y_edges = np.histogram2d(x, y, bins=(x_bins, y_bins), density=True)

    # Meshgrid for the bins
    X, Y = np.meshgrid(x_edges[:-1], y_edges[:-1])

    # Plot the 3D surface of the joint PDF
    fig = plt.figure(figsize=(10, 8))
    ax = fig.add_subplot(111, projection='3d')
    ax.plot_surface(X, Y, hist, cmap='viridis')

    # Label the axes
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('p_X_Y(x, y)')
    ax.set_title('3D Joint PDF of z = x + y')
    plt.show()

    # Step 2: Plot the empirical PDF of z
    plt.figure(figsize=(10, 6))
    plt.hist(z, bins=50, density=True, alpha=0.6, color='blue', label='Empirical PDF of z')

    # Step 3: Compute and plot the convolution of PDFs of x and y
    z_range = np.linspace(-10, 10, 1000)
    pdf_x = norm.pdf(z_range, loc=0, scale=1)
    pdf_y = norm.pdf(z_range, loc=0, scale=1)
    
    # Convolution of pdf_x and pdf_y
    pdf_z_convolution = convolve(pdf_x, pdf_y, mode='same') * (z_range[1] - z_range[0])

    plt.plot(z_range, pdf_z_convolution, 'r-', linewidth=2, label=r'Convolution of PDFs of x and y')
    
    # Add labels and legend
    plt.xlabel('z')
    plt.ylabel('PDF')
    plt.title('Empirical PDF of z and Theoretical Convolution of PDFs of x and y')
    plt.legend()
    plt.grid(True)
    plt.show()

# Example usage
generate_joint_gaussian_pdf(10000)
_images/941e39ed77028954329b393af2f1267c83df107fe7ce4f95679ebf6d19d0b824.png _images/13d0ae0fdc6ca43d723af5e536064c6a918d6608af7b65f6b8f79627201ebf42.png

Schonhoff’s Method#

  • This code generates a 2-dimensional (2D) joint Gaussian random variable (RV) and then computes and displays its empirical joint probability density function (PDF).

  • The random variables (RVs) generated are statistically independent, have zero mean, and unit variance.

  • The empirical PDF is obtained using a histogram-based method.

import numpy as np
import matplotlib.pyplot as plt

def generate_joint_gaussian_pdf(num):
    """
    Generate the empirical joint Gaussian PDF.

    Parameters:
    num (int): Number of random variables (RVs) to generate.

    Returns:
    numpy.ndarray: The empirical joint Gaussian PDF.
    """
    # Initialize arrays for storing the generated random variables
    x = np.zeros(num)
    y = np.zeros(num)

    # Generate the random variables using the Box-Muller transform
    for i in range(num):
        ui = np.random.rand()
        uq = np.random.rand()
        x[i] = np.sqrt(-2 * np.log(ui)) * np.cos(2 * np.pi * uq)
        y[i] = np.sqrt(-2 * np.log(ui)) * np.sin(2 * np.pi * uq)

    # Define the bins for the histogram
    x_bins = np.arange(-5, 5.5, 0.5)
    y_bins = np.arange(-5, 5.5, 0.5)

    # Compute the histograms
    nx, _ = np.histogram(x, bins=x_bins)
    ny, _ = np.histogram(y, bins=y_bins)

    # Compute the joint histogram (empirical joint PDF)
    joint_pdf = np.outer(nx, ny)

    # Normalize the joint histogram to approximate the joint PDF
    joint_pdf = joint_pdf * 4 / 1e8

    # Plotting the joint PDF
    X, Y = np.meshgrid(x_bins[:-1], y_bins[:-1])
    fig = plt.figure()
    ax = fig.add_subplot(111, projection='3d')
    ax.plot_surface(X, Y, joint_pdf, cmap='viridis')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('p_X_Y(x,y)')
    plt.show()

    return joint_pdf  # Ensure that the output is not printed automatically by assigning to a variable

# Example usage
# Call the function but do not display the result
_ = generate_joint_gaussian_pdf(1000)
_images/1cea0ed2ccb42e88c7d2d5cc0a81450faa1297ec84ecb2c7d21adb6fd824e189.png