Come campionare rapidamente X se exp (X) ~ Gamma?


12

Ho un semplice problema di campionamento, in cui il mio ciclo interno assomiglia a:

v = sample_gamma(k, a)

dove sample_gammacampioni dalla distribuzione Gamma per formare un campione di Dirichlet.

Funziona bene, ma per alcuni valori di k / a, alcuni dei underflow di calcolo a valle.

L'ho adattato per utilizzare le variabili dello spazio registro:

v = log(sample_gamma(k, a))

Dopo aver adattato tutto il resto del programma, funziona correttamente (almeno mi dà gli stessi esatti risultati sui casi di test). Tuttavia, è più lento di prima.

C'è un modo per campionare direttamente senza usare funzioni lente come log ( ) ? Ho provato a cercare su Google per questo, ma non so nemmeno se questa distribuzione abbia un nome comune (log-gamma?).X,exp(X)Gammalog()


Tutto quello che devi fare è dividere ogni gamma gamma per la loro somma. Come si verifica quindi il underflow? E in che modo il logaritmo risolve questo problema (non è possibile calcolare la somma senza esponenziare nuovamente)?
whuber

@whuber Nello spazio del registro, si calcola la somma e la si sottragga da ciascun elemento. Quindi, questo evita il primo punto di underflow. C'è un po 'di ulteriore elaborazione quando questi dirichlet servono come componenti della miscela e vengono moltiplicati di nuovo per piccoli numeri.
luispedro,

L'aggiunta dei registri è matematicamente errata: corrisponde alla moltiplicazione delle gamme anziché alla loro aggiunta. Sì, potresti ottenere risultati di lavoro, ma sicuramente non avranno una distribuzione Dirichlet! Ancora una volta, qual è esattamente la natura del underflow originale e quali calcoli stai facendo quando succede? Quali sono i valori reali con cui stai lavorando?
whuber

@whuber Potrei aver semplificato un po 'troppo la mia descrizione. Faccio sempre i {t = gamma (a, b); somma + = t; d [i] = log (t)}; log = log (somma); forall i {d [i] - = log; }. In precedenza, questo era underflow se un era molto piccolo.
luispedro,

Capito: per vicino a 0 sarai nei guai, qualunque cosa accada. Problema interessante! α
whuber

Risposte:


9

Si consideri una piccola forma parametro vicino 0, ad esempio α = 1 / 100 . Nell'intervallo tra 0 e α , e - α è approssimativamente 1 , quindi il Gamma pdf è approssimativamente x α - 1 d x / Γ ( α ) . Questo può essere integrato in un CDF approssimativo, F α ( x ) = x ααα=1/100αeα1xα1dx/Γ(α) . Invertendolo, vediamo unapotenza1/α: un esponente enorme. Perα=1/100questo provoca qualche possibilità di underflow (un valore a doppia precisione inferiore a10-300, più o meno). Ecco una trama della possibilità di ottenere underflow in funzione del logaritmo in base dieci diα:Fα(x)=xααΓ(α)1/αα=1/10010300α

inserisci qui la descrizione dell'immagine

Una soluzione è sfruttare questa approssimazione per generare variate di log (Gamma): in effetti, prova a generare una variazione di gamma e, se è troppo piccola, genera il suo logaritmo da questa distribuzione di potenza approssimativa (come mostrato di seguito). (Ripetere l'operazione ripetutamente fino a quando il registro non rientra nell'intervallo di underflow, in modo che sia un valido sostituto della variabile di underflow originale.) Per il calcolo di Dirichlet, sottrarre il massimo di tutti i logaritmi da ciascuno dei valori di log: questo ridimensiona implicitamente tutto il Gamma varia in modo da non influenzare i valori di Dirichlet. Tratta ogni registro risultante che è troppo piccolo (diciamo, inferiore a -100) come il registro di un vero zero. Esponenziare gli altri registri. Ora puoi procedere senza underflow.

Ci vorrà ancora più tempo di prima, ma almeno funzionerà!

αC=log(Γ(α))+log(α)αC

Poiché il parametro scale ridimensiona semplicemente la variabile, non vi è alcun problema a soddisfarla in queste procedure. Non è nemmeno necessario se tutti i parametri di scala sono uguali.

modificare

1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xyyz/xxxz0y1

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

Γ(α)

0<α<1Γ(α+1)1/αΓ(α)


1
Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1)log(u)Γ(α+1)

7

raα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_gammagsl_rng_uniform_pos(0,1)_pos

Pertanto, posso prendere il registro dell'ultima espressione e utilizzare

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

log()pow()1/a1/a


α

Ho modificato la mia risposta per includere ulteriori dettagli ora.
luispedro,

Grazie: ma cos'è "r"? (Si noti che la ricorsione è limitata: al massimo verrà effettuata una chiamata ricorsiva, poiché uno> 0 implica 1.0 + a> 1.)
whuber

r è il generatore di numeri casuali (da cui si ottengono i numeri casuali).
luispedro,

Γ(α+1)B(α,1)Γ(α)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.