Como obter uma amostra rápida do X se exp (X) ~ Gamma?

12

Eu tenho um problema de amostragem simples, onde meu loop interno se parece com:

v = sample_gamma(k, a)

onde sample_gammaamostras da distribuição Gamma para formar uma amostra de Dirichlet.

Funciona bem, mas para alguns valores de k / a, parte da computação a jusante é insuficiente.

Eu o adaptei para usar variáveis ​​de espaço de log:

v = log(sample_gamma(k, a))

Depois de adaptar todo o restante do programa, ele funciona corretamente (pelo menos fornece os mesmos resultados exatos nos casos de teste). No entanto, é mais lento do que antes.

Existe uma maneira de amostrar diretamente sem usar funções lentas como log ( ) ? Tentei pesquisar no Google, mas nem sei se essa distribuição tem um nome comum (log-gama?).X,exp(X)Gammalog()

luispedro
fonte
Tudo o que você precisa fazer é dividir cada variável gama pela soma. Como, então, ocorre o underflow? E como tomar o logaritmo resolve esse problema (você não pode computar a soma sem exponenciar de volta de qualquer maneira)?
whuber
@whuber No espaço de log, você calcula a soma e subtrai -a de cada elemento. Portanto, isso evita o primeiro ponto de fluxo insuficiente. Há um pouco de processamento adicional quando esses dirichlets servem como componentes de mistura e são multiplicados por pequenos números novamente.
Luispedro # 03
A adição dos logs é matematicamente incorreta: corresponde à multiplicação dos gama em vez de adicioná-los. Sim, você pode obter resultados funcionais, mas eles definitivamente não terão uma distribuição Dirichlet! Novamente, qual é exatamente a natureza do subfluxo original e que cálculos você está fazendo quando isso acontece? Quais são os valores reais com os quais você está trabalhando?
whuber
@ whuber Eu poderia ter simplificado um pouco demais na minha descrição. Faço tudo i {t = gama (a, b); soma + = t; d [i] = log (t)}; soma de log = log (soma); forall i {d [i] - = soma de logs; } Anteriormente, isso era insuficiente se um era muito pequeno.
Luispedro 7/03
Entendi: para próximo de 0, você terá problemas, não importa o quê. Problema interessante! α
whuber

Respostas:

9

Considere-se uma pequena forma parâmetro perto de 0, tal como α = 1 / 100 . No intervalo entre 0 e α , e - α é aproximadamente 1 , então o Gamma pdf é aproximadamente x α - 1 d x / Γ ( α ) . Isso pode ser integrado a um CDF aproximado, F α ( x ) = x ααα=1/100αeα1xα1dx/Γ(α) . Ao invertê-lo, vemos umapotência1/α: um enorme expoente. Paraα=1/100isso provoca alguma possibilidade de underflow (um valor de precisão dupla inferior a10-300, mais ou menos). Aqui está um gráfico da chance de ficar abaixo do fluxo em função do logaritmo da base dez deα:Fα(x)=xααΓ(α)1/αα=1/10010300α

enter image description here

Uma solução é explorar essa aproximação para gerar variáveis ​​logarítmicas (gama): na verdade, tente gerar uma variável gama e, se for muito pequena, gere seu logaritmo a partir dessa distribuição aproximada de energia (como mostrado abaixo). (Faça isso repetidamente até que o log esteja dentro do intervalo de subfluxo, de modo que seja um substituto válido para a variável original de subfluxo.) Para o cálculo do Dirichlet, subtraia o máximo de todos os logaritmos de cada um dos valores do log: a gama varia para não afetar os valores do Dirichlet. Trate qualquer log resultante que seja muito pequeno (digamos, menor que -100) como sendo o log de um zero verdadeiro. Exponencie os outros logs. Agora você pode prosseguir sem fluxo insuficiente.

Isso vai demorar ainda mais do que antes, mas pelo menos funcionará!

Para gerar um log aproximado gama variável com o parâmetro de forma , pré-calcule C = log ( Γ ( α ) ) + log ( α ) . Isso é fácil, porque existem algoritmos para calcular os valores do log Gamma diretamente . Gere uma flutuação aleatória uniforme entre 0 e 1, pegue seu logaritmo, divida por α e adicione C a ele.αC=log(Γ(α))+log(α)αC

Como o parâmetro de escala apenas redimensiona a variável, não há problema em acomodá-lo nesses procedimentos. Você nem precisa se todos os parâmetros de escala forem iguais.

Editar

Em outra resposta, o OP descreve um método no qual a potência de uma variável uniforme (uma variável B ( α ) ) é multiplicada por uma variável Γ ( α + 1 ) . Isso funciona porque o pdf da distribuição conjunta dessas duas variáveis ​​é igual a ( α x α - 1 ) ( y α e - y d y / Γ ( α + 1 ) ) . Para encontrar o pdf de z = x y1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xysubstituímos , dividimos pelo x jacobino e integramos x . A integral deve variar de z a porque 0 y 1 , de ondeyz/xxxz0y1

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

que é o pdf de uma distribuição .Γ(α)

O ponto principal é que, quando , é improvável que um valor extraído de Γ ( α + 1 ) seja insuficiente e somando seu log e 1 / α vezes o log de uma variável uniforme independente, teremos o log de um Varia ( α ) variável. É provável que o log seja muito negativo, mas teremos contornado a construção do seu antilog, que será transmitido em uma representação de ponto flutuante.0<α<1Γ(α+1)1/αΓ(α)

whuber
fonte
1
Apenas um argumento para tornar sua edição um pouco mais elegante, você realmente não precisa recorrer à integração aqui. Apenas use o fato de que , além de queΓ(α)+Γ(1)~Γ(α+1). Essas são propriedades padrão das distribuições beta e gama. Além disso, quandoα0temos aproximadamenteyexpo(1)Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1), que pode ser mais rápido para simular ( ) do que uma variável aleatória geral Γ ( α + 1 ) . log(u)Γ(α+1)
probabilityislogic
7

Estou respondendo minha própria pergunta, mas encontrei uma solução muito boa, mesmo que não a entenda completamente. Observando o código da GNU Scientific Library, eis como ele amostra variáveis ​​gama ( ré o gerador de números aleatórios, aé e é β ):α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

Portanto, eu posso pegar o log da última expressão e usar

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

log()pow()1/a1/a

luispedro
fonte
α
Editei minha resposta para incluir mais detalhes agora.
Luispedro
Obrigado: mas o que é "r"? (Note que a recursividade é limitado: no máximo uma chamada recursiva será feita, porque a> 0 implica 1.0 + a> 1.)
whuber
r é o gerador de números aleatórios (de onde você está obtendo os números aleatórios).
Luispedro #
Γ(α+1)B(α,1)Γ(α)