#python #random #probability #probability-distribution
#python #Случайный #вероятность #распределение вероятности
Вопрос:
Я совершенно новичок в Python. Может кто-нибудь показать мне, как я могу написать генератор случайных чисел, который выбирает из распределения Леви? Я написал функцию для распределения, но я не знаю, как действовать дальше! Случайные числа, сгенерированные этим распределением, я хочу использовать их для имитации случайного блуждания 2D.
Я знаю, что из scipy.stats я могу использовать класс Levy, но я хочу сам написать сэмплер.
import numpy as np
import matplotlib.pyplot as plt
# Levy distribution
"""
f(x) = 1/(2*pi*x^3)^(1/2) exp(-1/2x)
"""
def levy(x):
return 1 / np.sqrt(2*np.pi*x**3) * np.exp(-1/(2*x))
N = 50
foo = levy(N)
Комментарии:
1. Пока это просто кодирование формулы, а не фактическое написание сэмплера, поэтому на самом деле это не вопрос отладки. Из ваших исследований о том, как выполнять выборку, вы можете написать код, а затем вернуться с любыми проблемами, с которыми вы столкнетесь на этом пути.
2. Почему бы не использовать предоставленный генератор:
scipy.stats.levy.rvs(size=1)
?3. Учитывая равномерные (0, 1) выборки, стандартный подход к генерации выборок из другого распределения, которое имеет кумулятивную функцию распределения F, заключается в вычислении F ^ (- 1) (u), где u — равномерная выборка, а F ^ (- 1) — величина, обратная cdf. Пока у вас есть функция плотности; помните, что cdf F (x) является интегралом от плотности с точностью до x (или, может быть, вы можете просто посмотреть cdf).
4. @RobertDodier Вы можете показать мне, как это сделать на python?
5. @Advaita Ну, мне нравится давать подсказки об общем подходе. Я предполагаю, что вы можете проработать детали. Я думаю, первое, что нужно выяснить, это как реализовать обратное cdf. Похоже, что ссылка, данная pjs, содержит формулу для этого — вы могли бы поработать над ее реализацией.
Ответ №1:
код @pjs выглядит нормально для меня, но есть несоответствие между его кодом и тем, что SciPy думает о Леви — в основном, выборка отличается от PDF.
Код, Python 3.8 Windows 10 x64
import numpy as np
from scipy.stats import levy
from scipy.stats import norm
import matplotlib.pyplot as plt
rng = np.random.default_rng(312345)
# Arguments
# u: a uniform[0,1) random number
# c: scale parameter for Levy distribution (defaults to 1)
# mu: location parameter (offset) for Levy (defaults to 0)
def my_levy(u, c = 1.0, mu = 0.0):
return mu c / (2.0 * (norm.ppf(1.0 - u))**2)
fig, ax = plt.subplots()
rnge=(0, 20.0)
x = np.linspace(rnge[0], rnge[1], 1001)
N = 200000
q = np.empty(N)
for k in range(0, N):
u = rng.random()
q[k] = my_levy(u)
nrm = levy.cdf(rnge[1])
ax.plot(x, levy.pdf(x)/nrm, 'r-', lw=5, alpha=0.6, label='levy pdf')
ax.hist(q, bins=100, range=rnge, density=True, alpha=0.2)
plt.show()
создайте график
Обновить
Ну, я попытался использовать самодельный PDF, тот же результат, та же проблема
# replace levy.pdf(x) with PDF(x)
def PDF(x):
return np.where(x <= 0.0, 0.0, 1.0 / np.sqrt(2*np.pi*x**3) * np.exp(-1./(2.*x)))
ОБНОВЛЕНИЕ II
После применения исправленной процедуры выборки @pjs выборка и PDF идеально выровнены. Новый график
Ответ №2:
Вот простая реализация алгоритма генерации для распределения Леви, найденного в Википедии:
import random
from scipy.stats import norm
# Arguments
# u: a uniform[0,1) random number
# c: scale parameter for Levy distribution (defaults to 1)
# mu: location parameter (offset) for Levy (defaults to 0)
def my_levy(u, c = 1.0, mu = 0.0):
return mu c / (2 * norm.ppf(1.0 - u)**2)
# Generate a handful of samples
for _ in range(10):
print(my_levy(random.random()))
Обычно я не использую Python, поэтому, пожалуйста, предложите улучшения.
ДОБАВЛЕНИЕ
Благодарность Северину Паппаде за работу в его ответе. Я уже отмечал, что более простым ответом было бы взять обратную квадрату гауссова, но Адвайта попросил явную функцию U ~ Uniform(0,1), поэтому я не стал этого делать. Оказывается, я должен был. В Википедии упоминается об этом, но без масштабного коэффициента 2 в знаменателе. Когда я беру 2 из реализации алгоритма генерации Википедии, т. Е. Изменяю реализацию на
def my_levy(u, c = 1.0, mu = 0.0):
return mu c / (norm.ppf(1.0 - u)**2)
результирующая гистограмма прекрасно совпадает с нормализованным графиком pdf. (Примечание — теперь я также отредактировал неправильную запись в Википедии, чтобы исправить формулу.)
Комментарии:
1. могут возникнуть некоторые проблемы… (с чем?), Пожалуйста, взгляните на мой ответ. Я слишком устал, чтобы разобраться в этом сейчас, ложась спать.
2. @SeverinPappadeux Ты прав! В Википедии инверсия неправильная, она отклоняется в знаменателе в 2 раза.
3. Отлично! Обновлено новым графиком, теперь все идеально выровнено.