Jak szybko próbkować X, jeśli exp (X) ~ Gamma?

12

Mam prosty problem z próbkowaniem, w którym moja wewnętrzna pętla wygląda następująco:

v = sample_gamma(k, a)

gdzie sample_gammapróbki z rozkładu gamma tworzą próbkę Dirichleta.

Działa dobrze, ale w przypadku niektórych wartości k / a niektóre z niższych obliczeń są niedopełnione.

Dostosowałem go do używania zmiennych przestrzeni dziennika:

v = log(sample_gamma(k, a))

Po dostosowaniu całej reszty programu działa poprawnie (przynajmniej daje mi te same dokładne wyniki w przypadkach testowych). Jest jednak wolniejszy niż wcześniej.

Czy jest sposób na bezpośrednie próbkowanie bez użycia wolnych funkcji, takich jak ? Próbowałem google, ale nawet nie wiem, czy ta dystrybucja ma wspólną nazwę (log-gamma?).X,exp(X)Gammalog()

luispedro
źródło
Wszystko, co musisz zrobić, to podzielić każdą zmienną gamma przez ich sumę. Jak zatem występuje niedopełnienie? W jaki sposób przyjęcie logarytmu rozwiązuje ten problem (i tak nie można obliczyć sumy bez ponownego wykładnika)?
whuber
@ whuber W przestrzeni dziennika obliczasz sumę, a następnie odejmujesz ją od każdego elementu. Pozwala to uniknąć pierwszego punktu niedomiaru. Jest trochę dalszego przetwarzania, gdy te dirichlety służą jako składniki mieszaniny i ponownie zostają pomnożone przez małe liczby.
luispedro,
Dodawanie dzienników jest matematycznie niepoprawne: odpowiada raczej pomnożeniu gamma niż ich dodaniu. Tak, możesz uzyskać wyniki pracy, ale na pewno nie będą miały rozkładu Dirichleta! Znowu, jaka dokładnie jest natura pierwotnego niedomiaru i jakie obliczenia wykonujesz, kiedy to nastąpi? Jakie są rzeczywiste wartości, z którymi pracujesz?
whuber
@ whuber W moim opisie mogłem trochę za bardzo uprościć. Robię wszystko i {t = gamma (a, b); suma + = t; d [i] = log (t)}; logsum = log (suma); forall i {d [i] - = logsum; }. Wcześniej było to niedopełnione, jeśli a było bardzo małe.
luispedro,
Rozumiem: dla pobliżu 0 będziesz miał kłopoty bez względu na wszystko. Ciekawy problem! α
whuber

Odpowiedzi:

9

Rozważ mały parametr kształtu pobliżu 0, taki jak . W zakresie między 0 i , około , a więc jest w przybliżeniu gamma PDF . Można to zintegrować z przybliżonym CDF, . Odwracając go, widzimy potęgę : ogromny wykładnik. Dla powoduje to pewną szansę na niedopełnienie (wartość podwójnej precyzji mniejsza niż , więcej lub mniej). Oto wykres szansy na niedomiar w zależności od logarytmu dziesięciu podstawα = 1 / 100 α e - α 1 x α - 1 d x / Γ ( α ) F a ( x ) = x ααα=1/100αeα1xα1dx/Γ(α) 1/αα=1/10010-300αFα(x)=xααΓ(α)1/αα=1/10010300α :

wprowadź opis zdjęcia tutaj

Jednym z rozwiązań jest wykorzystanie tego przybliżenia do generowania zmiennych log (Gamma): w efekcie spróbuj wygenerować zmienną Gamma, a jeśli jest ona zbyt mała, wygeneruj jej logarytm z przybliżonego rozkładu mocy (jak pokazano poniżej). (Wykonuj tę czynność wielokrotnie, aż dziennik znajdzie się w zakresie niedomiaru, aby był to prawidłowy zamiennik oryginalnej wariacji niedomiaru.) W obliczeniach Dirichleta odejmij maksimum wszystkich logarytmów od każdej wartości logu: domyślnie przeskaluje się wszystkie Gamma zmienia się, więc nie wpłynie to na wartości Dirichleta. Traktuj każdy wynikowy dziennik, który jest zbyt mały (powiedzmy, mniejszy niż -100), jako dziennik prawdziwego zera. Potęguj inne dzienniki. Teraz możesz kontynuować bez niedomiaru.

To potrwa jeszcze dłużej niż wcześniej, ale przynajmniej zadziała!

Aby wygenerować przybliżony log Gamma, należy zmienić za pomocą parametru kształtu , obliczenie wstępne . Jest to łatwe, ponieważ istnieją algorytmy do obliczania wartości log Gamma bezpośrednio . Wygeneruj jednolity losowy zmiennoprzecinkowy od 0 do 1, weź jego logarytm, podziel przez i dodaj do niegoC = log ( Γ ( α ) ) + log ( α ) α CαC=log(Γ(α))+log(α)αC

Ponieważ parametr skali jedynie przeskalowuje zmienną, nie ma problemu z dostosowaniem jej w tych procedurach. Nie potrzebujesz go nawet, jeśli wszystkie parametry skali są takie same.

Edytować

W innej odpowiedzi OP opisuje metodę, w której moc wariantu jednolitego (zmienna ) jest mnożona przez . Działa to, ponieważ pdf wspólnej dystrybucji tych dwóch wariantów jest równy . Aby znaleźć pdf , podstawiamy , dzielimy przez jakobian i integrujemy . Całka musi zawierać się w przedziale od do ponieważ , skąd1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xyyz/xxxz0y1

pdf(z)=αΓ(α+1)z(xα/x)ex(z/x)α1dxdz=1Γ(α)zα1ezdz,

który jest pdf dystrybucji .Γ(α)

Chodzi o to, że gdy , wartość narysowana z jest mało prawdopodobna, a sumując log i razy log niezależnego munduru zmieniamy będzie miał zmienną . Dziennik będzie prawdopodobnie bardzo negatywny, ale ominiemy konstrukcję jego antilogu, który spadnie w reprezentacji zmiennoprzecinkowej.0<α<1Γ(α+1)1/αΓ(α)

Whuber
źródło
1
Po prostu argument, aby twoja edycja była bardziej elegancka, tak naprawdę nie musisz odwoływać się do integracji. Po prostu skorzystaj z faktu, że oraz że . Są to standardowe właściwości rozkładów beta i gamma. Ponadto, gdy mamy mniej więcej , co może być szybsze do symulacji ( ) niż ogólna zmienna losowa . Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1)log(u)Γ(α+1)
probabilityislogic
7

Odpowiadam na własne pytanie, ale znalazłem całkiem dobre rozwiązanie, nawet jeśli nie do końca je rozumiem. Patrząc na kod z Biblioteki Naukowej GNU, oto, jak pobiera próbki zmiennych gamma ( rjest to generator liczb losowych, ato i to ):αbβ

  if (a < 1)
    {
      double u = gsl_rng_uniform_pos (r);
      return gsl_ran_gamma (r, 1.0 + a, b) * pow (u, 1.0 / a);
   }

gsl_ran_gammajest funkcją, która zwraca losową próbkę gamma (więc powyższe jest wywołaniem rekurencyjnym), podczas gdy gsl_rng_uniform_poszwraca równomiernie rozłożoną liczbę w ( jest to wartość ściśle dodatnia, ponieważ gwarantuje się, że nie zwróci 0.0).(0,1)_pos

Dlatego mogę pobrać dziennik ostatniego wyrażenia i użyć go

return log(gsl_ran_gamma(r, 1.0 + a, b)) + log(u)/a;

Aby dostać to, czego chciałem. Mam teraz dwa log()połączenia (ale jedno mniej pow()), ale wynik jest prawdopodobnie lepszy. Wcześniej, jak zauważył whuber, miałem coś podniesionego do potęgi , potencjalnie ogromnej liczby. Teraz w przestrzeni logicznej mnożę przez . Tak więc jest mniej prawdopodobne, że będzie niedostateczne.1 / a1/a1/a

luispedro
źródło
Czy możesz wyjaśnić, co robią gsl_rng_uniform_pos i gsl_ran_gamma? Domyślam się, że pierwszy zwraca jednolitą losową wartość od 0 do r, a drugi jest związany z wartością Gamma (1 + a, b) - może to jest niepełna Gamma? Ogólnie rzecz biorąc, wygląda to bardzo zbliżone do przybliżenia, które zasugerowałem (z wyjątkiem tego, że podczas przeglądu jest oczywiste, że zapomniałem określić podział przez część , co jest istotne!)α
whuber
Zredagowałem swoją odpowiedź, aby teraz podać więcej szczegółów.
luispedro 16.03.11
Dziękuję: ale co to jest „r”? (Uwaga: rekursja jest ograniczona: zostanie wykonane co najwyżej jedno wywołanie rekurencyjne, ponieważ a> 0 oznacza 1,0 + a> 1.)
whuber
r jest generatorem liczb losowych (skąd otrzymujesz liczby losowe).
luispedro 16.03.11
Ach, to jest sprytne: iloczyn i niezależnej odmiany okazuje się być . Zredagowałem swoją odpowiedź, aby wskazywała na twoje rozwiązanie i wyjaśnia, dlaczego to działa. B ( α , 1 ) Γ ( α )Γ(α+1)B(α,1)Γ(α)
whuber