Я хотел бы взять образцы из распределения вероятностей с помощью CDF 1 - e^(-x^2)
.
Есть ли метод в python/scipy/etc. чтобы вы могли выбирать из распределения вероятностей, учитывая только его CDF?
Я хотел бы взять образцы из распределения вероятностей с помощью CDF 1 - e^(-x^2)
.
Есть ли метод в python/scipy/etc. чтобы вы могли выбирать из распределения вероятностей, учитывая только его CDF?
Чтобы создать собственный класс случайных переменных с учетом CDF, вы можете создать подкласс scipy.rv_continuous
и переопределить rv_continuous._cdf
. Это автоматически сгенерирует соответствующий PDF-файл и другую статистическую информацию о вашем дистрибутиве, например.
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()
Чтобы дополнить решение Heike, вы можете использовать выборку с обратным преобразованием для выборки через 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()
Мне было очень любопытно посмотреть, как это работает и в SciPy. На самом деле похоже, что он делает что-то очень похожее на вышеизложенное. На основе документов SciPy:
Метод по умолчанию _rvs основан на обратном cdf, _ppf, применяемом к однородной случайной переменной. Чтобы эффективно генерировать случайные переменные, необходимо либо перезаписать _ppf по умолчанию (например, если обратный cdf может быть выражен в явной форме), либо метод выборки должен быть реализован в пользовательском методе _rvs.
И на основе исходного кода SciPy, _ppf
(т. е. обратный CDF) на самом деле выглядит аппроксимированным численно, если не указано явно. Очень круто!