如果exp(X)〜Gamma如何快速采样X?


12

我有一个简单的采样问题,我的内循环看起来像:

v = sample_gamma(k, a)

其中sample_gamma从Gamma分布样品以形成样品狄利克雷。

它运行良好,但对于某些k / a值,一些下游计算会出现下溢。

我将其修改为使用日志空间变量:

v = log(sample_gamma(k, a))

在修改了该程序的所有其余部分之后,它可以正常工作(至少在测试案例中它给我的结果是相同的)。但是,它比以前慢。

有没有一种方法可以直接对进行采样而无需使用这样的慢函数?我为此进行了谷歌搜索,但是我什至不知道此发行版是否具有通用名称(log-gamma?)。对数X,exp(X)Gammalog()


您需要做的就是将每个伽玛变量除以它们的总和。那么,下溢如何发生?对数如何解决这个问题(您不能在不再次取幂的情况下计算总和)?
ub

@whuber在日志空间中,计算总和,然后从每个元素中减去它。因此,这避免了下溢的第一点。当这些狄利克雷特作为混合成分并再次乘以小数时,会有一些进一步的处理。
luispedro 2011年

从数学上来说,添加日志是不正确的:它对应于乘以 gamma而不是将其相加。是的,您可能会得到工作结果,但是它们肯定不会具有Dirichlet分布!同样,原始下溢的性质到底是什么?发生这种情况时您要进行什么计算?您正在使用的实际值是多少?
ub

@whuber我的描述可能已经简化了很多。我全力以赴{{= gamma(a,b); 和+ = t; d [i] = log(t)}; logsum = log(sum); forall i {d [i]-= logum; }。以前,如果a很小,则会下溢。
luispedro 2011年

知道了:如果接近0,无论如何您都会遇到麻烦。有趣的问题!α
ub

Answers:


9

考虑一个接近0 的小形状参数,例如。在0到之间的范围内,大约为,因此Gamma pdf大约为。这可以集成到近似CDF中,。取反,我们看到一个幂:一个巨大的指数。对于这会引起下溢的可能性(双精度值小于或等于)。这是下溢的概率图,是底数的十进制对数的函数α = 1 / 100 α ë - α 1 X α - 1 d X / Γ α ˚F αX = X ααα=1/100αeα1xα1dx/Γ(α) 1/αα=1/10010-300αFα(x)=xααΓ(α)1/αα=1/10010300α

在此处输入图片说明

一种解决方案是利用这种近似来生成log(Gamma)变量:实际上,尝试生成Gamma变量,如果它太小,则根据此近似功率分布生成其对数(如下所示)。(重复执行此操作,直到对数在下溢范围内,以便它可以有效替代原始下溢变量。)对于Dirichlet计算,请从每个对数值中减去所有对数的最大值:这将隐式重新缩放所有比例Gamma变量,因此不会影响Dirichlet值。将所得的任何太小(例如小于-100)的对数视为真实零的对数。对其他日志求幂。现在,您可以继续进行而不会发生下溢。

这将花费比以前更长的时间,但至少它会起作用!

要生成形状参数为的近似对数伽玛变量,请预先计算。这很容易,因为有一些算法可以直接计算log Gamma的值。生成0和1之间的均匀随机浮子,取其对数,除以,并添加到它。Ç = 日志Γ α + 日志α ααC=log(Γ(α))+log(α)αC

因为scale参数只是重新缩放变量,所以在这些过程中将其容纳起来没有问题。如果所有比例参数都相同,则甚至不需要它。

编辑

OP在另一个答复中描述了一种方法,其中将统一变量(变量)的幂乘以变量。这是可行的,因为这两个变量的联合分布的pdf等于。为了找到的pdf,我们将,除以雅可比,然后积分出。积分的范围必须从到因为,因此1/αB(α)Γ(α+1)(αxα1)(yαeydy/Γ(α+1))z=xyyz/xxxz0y1

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

这是分布的pdf 。Γ(α)

整点是,当,从得出的值不太可能下溢,并且通过将其对数和乘以独立均变量的对数来求和,将具有变量的对数。该对数可能非常负,但是我们将绕过其对数的构造,该对数将以浮点表示形式下溢。0<α<1Γ(α+1)1/αΓ(α)


1
只是使您的编辑更加美观的一个论点,您实际上并不需要在这里呼吁集成。只需使用加上事实。这些都是beta和gamma分布的标准属性。同样,当我们大约有,它比一般的随机变量要快()。Γ(α)Γ(α)+Γ(1)Beta(α,1)Γ(α)+Γ(1)Γ(α+1)α0yexpo(1)log(u)Γ(α+1)
概率

7

我正在回答自己的问题,但是即使我不完全了解,我还是找到了一个很好的解决方案。看着从GNU科学图书馆代码,这里是它的样本伽马变量是如何(r是随机数发生器,a是和为):α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_gamma是返回伽马随机样品(因此上述是一个递归调用)的函数,而gsl_rng_uniform_pos返回以均匀分布的数(该为,因为它是保证不返回0.0严格为正)。(0,1)_pos

因此,我可以获取最后一个表达式的日志并使用

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

得到我想要的。我现在有两个log()电话(但少一个pow()),但结果可能更好。正如胡布尔指出的那样,以前我曾提出过的幂,可能是一个很大的数目。现在,在logspace中,我乘以。因此,它不太可能发生下溢。1 /1/a1/a


您能解释一下gsl_rng_uniform_pos和gsl_ran_gamma做什么吗?我猜第一个返回的是介于0和r之间的均匀随机值,第二个返回的是与Gamma(1 + a,b)值相关的-也许是不完整的Gamma?总体而言,这看起来与我建议的近似值非常接近(但α
在进行

我编辑了答案,现在包括更多详细信息。
luispedro 2011年

谢谢:但是“ r”是什么?(请注意,递归是有界的:最多将进行一个递归调用,因为a> 0表示1.0 + a>1。)
whuber

r是随机数生成器(从中获取随机数)。
luispedro 2011年

啊,这很聪明:和一个独立的变量的乘积原来是变量。我修改了我的回复,以使其指向您的解决方案,并解释了为什么可行。B α 1 Γ α Γ(α+1)B(α,1)Γ(α)
ub
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.