У меня есть простая проблема выборки, где мой внутренний цикл выглядит так:
v = sample_gamma(k, a)
где sample_gamma
образцы из гамма-распределения, чтобы сформировать образец Дирихле.
Это работает хорошо, но для некоторых значений k / a некоторые из последующих вычислений теряются.
Я адаптировал его для использования переменных пространства журнала:
v = log(sample_gamma(k, a))
После адаптации всей остальной программы она работает правильно (по крайней мере, она дает мне те же точные результаты в тестовых случаях). Тем не менее, это медленнее, чем раньше.
Есть ли способ напрямую сэмплировать без использования медленных функций, таких как ? Я попробовал поискать в Google, но я даже не знаю, имеет ли этот дистрибутив общее имя (log-gamma?).журнал ( )
sampling
gamma-distribution
luispedro
источник
источник
Ответы:
Рассмотрим небольшой параметр формы около 0, такой как . В диапазоне между 0 и , приблизительно , так что гамма PDF приблизительно . Это может быть интегрировано в приблизительный CDF, . Обращая его, мы видим степень : огромный показатель. Для это вызывает некоторую вероятность недостаточного значения (значение двойной точности меньше , более или менее). Вот график вероятности недосыпания в зависимости от логарифма по основанию-десяти& alpha ; = 1 / 100 & alpha ; е - & alpha ; 1 х & alpha ; - 1 г х / Γ ( & alpha ; ) F & alpha ; ( х ) = х & alpha ;α α=1/100 α e−α 1 xα−1dx/Γ(α) 1/& alpha& alpha=1/10010-300& alphaFα(x)=xααΓ(α) 1/α α=1/100 10−300 α :
Одно из решений состоит в том, чтобы использовать это приближение для генерации логарифмических (гамма-вариаций): по сути, попробуйте сгенерировать гамма-вариацию и, если она слишком мала, сгенерировать ее логарифм из этого приблизительного распределения мощности (как показано ниже). (Повторяйте это до тех пор, пока журнал не окажется в пределах диапазона недостаточного заполнения, чтобы он являлся допустимой заменой исходной переменной пониженного значения.) Для вычисления Дирихле вычтите максимум всех логарифмов из каждого значения журнала: это неявно изменяет масштаб всех гамма изменяется, поэтому она не влияет на значения Дирихле. Обрабатывайте любой получающийся журнал, который слишком мал (скажем, меньше -100), как журнал с истинным нулем. Экспонировать другие журналы. Теперь вы можете продолжить без потери.
Это займет еще больше времени, чем раньше, но по крайней мере это сработает!
Чтобы сгенерировать приблизительный журнал Gamma варьировать с параметром формы , предварительно вычислите . Это легко, потому что существуют алгоритмы для непосредственного вычисления значений log Gamma . Создайте случайное число с плавающей точкой между 0 и 1, возьмите его логарифм, разделите на и добавьте к немуα C=log(Γ(α))+log(α) α C
Поскольку параметр масштаба просто изменяет масштаб переменной, нет проблем с его размещением в этих процедурах. Вам даже не нужно, если все параметры шкалы одинаковы.
редактировать
В другом ответе OP описывает метод, в котором степень равномерной переменной (переменная ) умножается на переменную . Это работает, потому что pdf совместного распределения этих двух переменных равен . Чтобы найти pdf из мы подставляем , делим на хакобейский и интегрируем из . Интеграл должен находиться в диапазоне от до потому что , откуда1/α B(α) Γ(α+1) (αxα−1)(yαe−ydy/Γ(α+1)) z=xy y→z/x x x z ∞ 0≤y≤1
который является pdf дистрибутива .Γ(α)
Все дело в том, что когда , значение, полученное из , вряд ли будет недооценено, и, суммируя его log и раз логарифм независимой равномерной переменной, мы будет иметь журнал изменений . Журнал, скорее всего, будет очень отрицательным, но мы обойдем конструкцию его антилога, который будет потерян в представлении с плавающей запятой.0<α<1 Γ(α+1) 1/α Γ(α)
источник
Я отвечаю на свой вопрос, но нашел довольно хорошее решение, даже если не до конца его понимаю. Глядя на код из Научной библиотеки GNU, мы рассмотрим примеры гамма-переменных (α β
r
это генератор случайных чисел,a
это и is ):b
gsl_ran_gamma
является функцией, которая возвращает гамма-случайную выборку (поэтому вышеупомянутый является рекурсивным вызовом), в то время какgsl_rng_uniform_pos
возвращает равномерно распределенное число в ( для строго положительного, поскольку гарантированно не вернет 0.0)._pos
Поэтому я могу взять журнал последнего выражения и использовать
Чтобы получить то, что я хотел. У меня сейчас два1/a 1/a
log()
звонка (но на один меньшеpow()
), но результат, вероятно, лучше. До того, как указал Уубер, у меня было что-то повышенное до , потенциально огромное количество. Теперь в logspace я умножаю на . Таким образом, это меньше шансов на снижение.1 / aисточник