Cara mengambil sampel dari distribusi yang diberikan CDF dengan Python

Saya ingin mengambil sampel dari distribusi probabilitas dengan CDF 1 - e^(-x^2).

Apakah ada metode di python/scipy/etc. untuk memungkinkan Anda mengambil sampel dari distribusi probabilitas hanya dengan CDF-nya?


person fomin    schedule 06.03.2020    source sumber
comment
Saya agak berkarat, tetapi jika saya ingat, CDF merupakan bagian integral dari PDF. Jadi ini sepertinya pertanyaan aljabar. Mungkin: wolframalpha.com/input/?i=d%2Fdx+%281+-+e%5E%28-x%5E2%29%29   -  person pinegulf    schedule 06.03.2020
comment
@pinegulf Terima kasih, tetapi bagaimana cara Anda melakukan pengambilan sampel?   -  person fomin    schedule 06.03.2020
comment
baik, karena Anda mengetahui CDF pada nilai X, Anda dapat melakukan perulangan di mana Anda melakukan beberapa langkah dan mencari tahu berapa nilai PDF karena Anda mengetahui delta CDF.   -  person pinegulf    schedule 06.03.2020


Jawaban (2)


Untuk membuat kelas variabel acak khusus yang diberi CDF, Anda dapat membuat subkelas scipy.rv_continuous dan mengganti rv_continuous._cdf. Ini kemudian akan secara otomatis menghasilkan PDF yang sesuai dan informasi statistik lainnya tentang distribusi Anda, misalnya.

import matplotlib.pyplot as plt
import numpy as np
from scipy import stats

class MyRandomVariableClass(stats.rv_continuous):
    def __init__(self, xtol=1e-14, seed=None):
        super().__init__(a=0, xtol=xtol, seed=seed)

    def _cdf(self, x):
        return 1-np.exp(-x**2)


if __name__ == "__main__":
    my_rv = MyRandomVariableClass()

    # sample distribution
    samples = my_rv.rvs(size = 1000)

    # plot histogram of samples
    fig, ax1 = plt.subplots()
    ax1.hist(list(samples), bins=50)

    # plot PDF and CDF of distribution
    pts = np.linspace(0, 5)
    ax2 = ax1.twinx()
    ax2.set_ylim(0,1.1)
    ax2.plot(pts, my_rv.pdf(pts), color='red')
    ax2.plot(pts, my_rv.cdf(pts), color='orange')

    fig.tight_layout()
    plt.show()

person Heike    schedule 06.03.2020
comment
Wah, sungguh luar biasa. Tahukah Anda cara melakukannya (yaitu membuat PDF dan juga memberikan cara untuk mengambil sampelnya)? Dengan asumsi itu tidak benar-benar melakukan diferensiasi apa pun, itu pasti merupakan perkiraan numerik. - person fomin; 06.03.2020

Pengambilan Sampel Transformasi Terbalik

Untuk menambahkan solusi Heike, Anda dapat menggunakan Inverse Transform Sampling untuk mengambil sampel melalui CDF :

import math, random
import matplotlib.pyplot as plt

def inverse_cdf(y):
    # Computed analytically
    return math.sqrt(math.log(-1/(y - 1)))

def sample_distribution():
    uniform_random_sample = random.random()
    return inverse_cdf(uniform_random_sample)

x = [sample_distribution() for i in range(10000)]
plt.hist(x, bins=50)
plt.show()

Bagaimana SciPy Melakukannya

Saya juga sangat penasaran untuk melihat cara kerjanya di SciPy. Tampaknya ia melakukan sesuatu yang sangat mirip dengan yang di atas. Berdasarkan dokumen SciPy:

Metode default _rvs bergantung pada kebalikan dari cdf, _ppf, yang diterapkan pada variasi acak seragam. Untuk menghasilkan variasi acak secara efisien, _ppf default perlu ditimpa (misalnya jika cdf invers dapat dinyatakan dalam bentuk eksplisit) atau metode pengambilan sampel perlu diterapkan dalam metode _rvs khusus.

Dan berdasarkan kode sumber SciPy, _ppf (yaitu kebalikan dari CDF) sebenarnya terlihat diperkirakan secara numerik jika tidak ditentukan secara eksplisit. Sangat keren!

person Jeff N    schedule 14.03.2021