目前正在讨论当前的np.random.dirichlet
函数,因为它不适用于小参数:
In [1]: import numpy as np
In [2]: np.random.dirichlet(np.ones(3)*.00001)
---------------------------------------------------------------------------
ZeroDivisionError Traceback (most recent call last)
<ipython-input-2-464b0fe9c6c4> in <module>()
----> 1 np.random.dirichlet(np.ones(3)*.00001)
mtrand.pyx in mtrand.RandomState.dirichlet (numpy/random/mtrand/mtrand.c:25213)()
mtrand.pyx in mtrand.RandomState.dirichlet (numpy/random/mtrand/mtrand.c:25123)()
ZeroDivisionError: float division
讨论可以阅读这里和这里,并指出这是一个规范化错误。目前,由于几个原因,提议的小参数交换采样器的增强不能合并到numpy的主目录中。
问题:有人能建议在python中绘制dirichlet的另一种方法吗?或者向我指出一个解决方案,在不重新编译我的numpy和/或处理未发布的分支的情况下使用新的取样器?
发布于 2015-11-12 17:38:24
好的,让我们尝试以下几点。这是beta(α,beta)变量抽样,它适用于任何小的数字。
import math
import random
def sample_beta(alpha, beta):
x = math.log( random.random() )
y = math.log( random.random() )
return x / (x + y*alpha/beta)
# some testing
import matplotlib.pyplot as plt
bins = [0.01 * i for i in range(102)]
plt.hist([sample_beta(0.00001, 0.1) for k in range(10000000)], bins)
plt.show()
使用它,您可以尝试通过Beta变量对Dirichlet进行采样,如维基百科所述。
params = [a1, a2, ..., ak]
xs = [sample_beta(params[0], sum(params[1:]))]
for j in range(1,len(params)-1):
phi = sample_beta(params[j], sum(params[j+1:]))
xs.append((1-sum(xs)) * phi)
xs.append(1-sum(xs))
如果它有效,可以对其进行优化,使所有的部分和都预先计算出来。
更新
以上抽样依赖于这样的事实,即可以通过β变量对Dirichlet进行采样,如果参数较小,这是更好(但更慢)的选择。反过来,β变量可以抽样为一对伽马变量:
beta(a, b) = gamma(1, a) / (gamma(1, a) + gamma(1, b))
因此,小参数从伽玛中的第一位(如果你通过伽玛变量直接采样Dirichlet )移动到第二位。1(1)在伽玛变量中处于第一位意味着它们只是指数分布,采样为-log(0,1)。请检查一下我的数学是否正常,但那样的话抽样可能有效。
https://stackoverflow.com/questions/33648520
复制