Написать генератор случайных чисел, который на основе равномерно распределенных чисел от 0 до 1 выбирает выборки из распределения Леви?

#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. Отлично! Обновлено новым графиком, теперь все идеально выровнено.