是否允许64位或更多位的numpy.random.binomial?

时间:2014-05-20 17:10:17

标签: python python-3.x numpy random

我需要根据二项分布随机生成一系列数字。 Numpy的随机套件提供了一种方法来实现这一点,但遗憾的是它似乎仅限于处理 n 值的32位数字,我想处理该范围之外的值。 64位应该足够了,尽管任意更高的精度也可以正常工作。

示例输出:

>>> np.random.binomial(1<<40, 0.5)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "mtrand.pyx", line 3506, in mtrand.RandomState.binomial (numpy\random\mtrand\mtrand.c:16555)
OverflowError: Python int too large to convert to C long

我可以使用替代品吗?或者这种随机生成器内部使用64位数字的方法是什么?

或者我是否需要自己兜售?

(正如Robert Klein指出的那样,除了Windows之外,numpy在64位平台上做了64位;不幸的是我使用的是Windows)。

2 个答案:

答案 0 :(得分:2)

在C long整数为64位的机器上,numpy.random.binomial()将接受并生成64位整数。除Windows之外的大多数64位平台都是这样。例如,在我的64位OS X机器上:

[~]
|11> np.random.binomial(1 << 40, 0.5)
549755265539

[~]
|12> np.random.binomial(1 << 40, 0.5) > (1<<32)
True

或者,如果您遇到Windows,请考虑将Normal Approximation用于二项分布。如此大的n,近似值应该非常好。

def approx_binomial(n, p, size=None):
    gaussian = np.random.normal(n*p, n*p*(1-p), size=size)
    # Add the continuity correction to sample at the midpoint of each integral bin.
    gaussian += 0.5
    if size is not None:
        binomial = gaussian.astype(np.int64)
    else:
        # scalar
        binomial = int(gaussian)
    return binomial

答案 1 :(得分:1)

有一个精确有效的采样器可以生成二项式( n ,1/2)随​​机变量,即使 n 很大,如Bringmann等人所述。 2014。与该论文中描述的算法等效的算法如下:

  1. 如果 n 小于4,则生成 n 无偏随机位(零或一)并返回其总和。否则,如果 n 为奇数,则使用 n = n − 1将 ret 设置为该算法的结果。然后将无偏随机位的值添加到 ret ,然后返回 ret
  2. m 设置为floor(sqrt( n ))+ 1。
  3. (首先,从二项式曲线的包络中进行采样。)生成无偏的随机位(零或一),直到以此方式生成零为止。将 k 设置为以此方式生成的数量。
  4. s 设置为随机选择的[0, m )中的整数,然后将 i 设置为 k * m + s
  5. ret 设置为 n / 2 + i n / 2- i < / em> − 1的概率相等。
  6. (第二,接受或拒绝 ret 。)如果 ret <0或 ret > n ,请转到进行第3步。
  7. 有概率选择( n ret )* m * 2 k -< em> n )+ 2 ,返回 ret 。否则,请转到步骤3。(在这里,select( n k )是一个二项式系数。下面的Python代码计算该概率的对数。)

(请注意,Bringmann论文的算法比此算法更复杂,部分是为了避免由于精度有限而导致的舍入误差,Farach-Colton和Tsai [2015]展示了如何对二项式( n < / em>, p )任意 p 的随机变量可以简化为抽样二项式( n ,1/2)变量的问题。有关更多详细信息,请参阅这些论文或我的笔记“ On a Binomial Sampler”。)

以下是二项(1/2)算法的纯Python实现,它不依赖底层操作系统的32位/ 64位支持。

import random
import math

def binomhalf(n):
   if n<4: return sum(random.randint(0,1) for i in range(n))
   if n%2==1: return random.randint(0,1)+binomhalf(n-1)
   m=int(math.sqrt(n))+1
   while True:
      k=0
      while random.randint(0,1)==0: k+=1
      i=k*m+random.randint(0,m-1)
      ret=n//2+i if random.randint(0,1)==0 else n//2-i-1
      if ret<0 or ret>n: continue
      expo=-random.expovariate(1)
      p=math.lgamma(n+1)-math.lgamma(ret+1)-math.lgamma((n-ret)+1)+ \
          math.log(m)+math.log(2)*((k-n)+2)
      if expo<=p: return ret

参考:

  • K。 Bringmann,F。Kuhn等人,“内部DLA:物理生长模型的有效模拟。”在:过程。 2014年,第41届国际自动机,语言和程序设计座谈会(ICALP'14)
  • Farach-Colton,M。和Tsai,M.T.,2015年。精确的亚线性二项式抽样。 Algorithmica 73(4),第637-651页。