Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create samples from trapezoidal probability density function

I have defined my probability density function as follows:

def trapezoidal_pdf(x, a, b, c, d):
    const = (2 / (d + c - a - b))
    
    if a <= x < b:
        probability = const * (x - a) / (b - a)
        return probability
    elif b <= x < c:
        probability = const
        return probability
    elif c <= x < d:
        probability = const * (d - x) / (d - c)
        return probability
    else:
        return 0.0  # Outside the defined range, probability is 0

How do I get samples from the pdf so when I plot the histogram it looks like a trapezoid?

I have tried using np.random.random, but I think that's not what I want

like image 977
Fazlur Rahman Avatar asked Nov 28 '25 14:11

Fazlur Rahman


1 Answers

ok, let me do a quick try, following https://en.wikipedia.org/wiki/Trapezoidal_distribution.

You could look at PDF (and CDF) of the distribution, and there are three distinctive parts - first triangle, middle box, last triangle. And you could sample in the first step what part you sample from, and then sample it from part distribution. Middle part is easy, just a scaled uniform, and side triangles are not hard either

Along the lines, not optimized, Python 3.11 Win x64

import numpy as np
import matplotlib.pyplot as plt

def select_part(abcd, rv: np.float64) -> int:
    a, b, c, d = abcd
    
    den = 1.0/(d + c - a - b)
    
    a1 = (b-a)*den
    a2 = 1.0 - (d - c)*den
    a3 = 1.0
    
    if rv <= a1:
        return 1
    
    if rv <= a2:
        return 2
    
    if rv <= a3:
        return 3
    
    return -1 # just in case, should never happen

def sample_trap(abcd, rv1: np.float64, rv2: np.float64) -> np.float64:
    a, b, c, d = abcd
    
    part = select_part(abcd, rv1)
    
    if part == 1:
        return a + np.sqrt(rv2)*(b - a)
    
    if part == 2:
        return b + (c-b)*rv2
    
    if part == 3:
        return d - np.sqrt(rv2)*(d - c)
    
    return -999999.0 
        
rng = np.random.default_rng(135797531)

abcd = (-2., 0., 1., 2.)

N = 1000000

res = np.empty(N)

for k in range(0, N):
    rv1 = rng.random()
    rv2 = rng.random()
    res[k] = sample_trap(abcd, rv1, rv2)

fig, axs = plt.subplots(1, 2, tight_layout=True)

axs[0].hist(res, bins=50)

and you should get something like

enter image description here

like image 143
Severin Pappadeux Avatar answered Nov 30 '25 03:11

Severin Pappadeux



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!