¿Cómo muestrear rápidamente X si exp (X) ~ Gamma?

12

Tengo un problema de muestreo simple, donde mi bucle interno se ve así:

v = sample_gamma(k, a)

donde sample_gammamuestras de la distribución Gamma para formar una muestra de Dirichlet.

Funciona bien, pero para algunos valores de k / a, algunos de los flujos de cálculo aguas abajo.

Lo adapté para usar variables de espacio de registro:

v = log(sample_gamma(k, a))

Después de adaptar todo el resto del programa, funciona correctamente (al menos me da los mismos resultados exactos en casos de prueba). Sin embargo, es más lento que antes.

¿Hay alguna forma de muestrear directamente sin usar funciones lentas como ? Intenté buscar en Google para esto, pero ni siquiera sé si esta distribución tiene un nombre común (log-gamma?).Registro gamma ( )X,exp(X)Gammalog()

luispedro
fuente
Todo lo que necesita hacer es dividir cada variante gamma por su suma. ¿Cómo, entonces, ocurre el desbordamiento? ¿Y cómo tomar el logaritmo resuelve este problema (no se puede calcular la suma sin exponer de nuevo de todos modos)?
whuber
@whuber En el espacio de registro, calcula la suma y luego la resta de cada elemento. Entonces, esto evita el primer punto de desbordamiento. Hay un poco de procesamiento adicional cuando estos dirichlets sirven como componentes de mezcla y se multiplican por pequeños números nuevamente.
luispedro
Agregar los registros es matemáticamente incorrecto: corresponde a multiplicar los gammas en lugar de agregarlos. Sí, puede obtener resultados de trabajo, ¡pero definitivamente no tendrán una distribución Dirichlet! Nuevamente, ¿cuál es exactamente la naturaleza del flujo inferior original y qué cálculos está haciendo cuando sucede? ¿Cuáles son los valores reales con los que está trabajando?
whuber
@whuber Podría haber simplificado demasiado mi descripción. Yo hago todo i {t = gamma (a, b); suma + = t; d [i] = log (t)}; logsum = log (suma); forall i {d [i] - = logsum; }. Anteriormente, esto se desbordaba si a era muy pequeño.
luispedro
Lo tengo: para cerca de 0 tendrás problemas sin importar qué. Problema interesante! α
whuber

Respuestas:

9

Considere una pequeña forma parámetro cerca de 0, tal como α = 1 / 100 . En el rango entre 0 y α , e - α es aproximadamente 1 , por lo que el Gamma pdf es aproximadamente x α - 1 d x / Γ ( α ) . Esto se puede integrar a un CDF aproximado, F α ( x ) = x ααα=1/100αeα1xα1dx/Γ(α) . Al invertirlo, vemos unapotencia1/α: un gran exponente. Paraα=1/100esto causa alguna posibilidad de underflow (un valor de doble precisión de menos de10-300, más o menos). Aquí hay una gráfica de la posibilidad de obtener un flujo inferior en función del logaritmo de base diez deα:Fα(x)=xααΓ(α)1/αα=1/10010300α

ingrese la descripción de la imagen aquí

Una solución es explotar esta aproximación para generar variables log (Gamma): en efecto, intente generar una variante Gamma y, si es demasiado pequeña, generar su logaritmo a partir de esta distribución de potencia aproximada (como se muestra a continuación). (Haga esto repetidamente hasta que el registro esté dentro del rango de flujo inferior, de modo que sea un sustituto válido para la variante de flujo inferior original). Para el cálculo de Dirichlet, reste el máximo de todos los logaritmos de cada uno de los valores de registro: esto reescala implícitamente todos Gamma varía para que no afecte los valores de Dirichlet. Trate cualquier registro resultante que sea demasiado pequeño (digamos, menor que -100) como el registro de un cero verdadero. Exponga los otros registros. Ahora puede continuar sin desbordamiento.

Esto llevará más tiempo que antes, ¡pero al menos funcionará!

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

Debido a que el parámetro de escala simplemente reescala la variante, no hay problema para acomodarla en estos procedimientos. Ni siquiera lo necesita si todos los parámetros de escala son iguales.

Editar

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/αΓ(α)

whuber
fuente
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

Por lo tanto, puedo tomar el registro de la última expresión y usar

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

log()pow()1/a1/a

luispedro
fuente
α
Edité mi respuesta para incluir más detalles ahora.
luispedro
Gracias: ¿pero qué es "r"? (Tenga en cuenta que la recursividad está limitada: como máximo se realizará una llamada recursiva, porque a> 0 implica 1.0 + a> 1.)
whuber
r es el generador de números aleatorios (de donde obtiene los números aleatorios).
luispedro
Γ(α+1)B(α,1)Γ(α)