在numpy中生成随机int64数组的最简单方法是什么?

8
我想创建一个 int64 类型的随机数组,使其在不在 int32 范围内的某个范围内均匀分布。
randintrandom_integers 但它们只能用于 int32;如果提供较大的上限,则会出现 "high is out of bounds for int32" 的错误提示。
如何生成指定范围内的随机 int64 数组?
可能的解决方案:
  • 使用浮点数生成器。但这种情况下分辨率是否足够好?
  • 生成随机字节,将其解释为 int64 数组,然后通过 lower + x % (upper - lower) 进行归一化。但是,int32 生成是否具有相同的归一化效果?它是否会影响均匀性?
还有更简洁方便的方法吗?
为什么随机方法只产生 floatsint32s

1
如果您使用密码学上安全的 PRNG(例如 SystemRandom),那么选项 B 应该是安全的。 - zwol
1
相关的,也许是重复的,但是旧的并没有任何真正“好”的答案:https://dev59.com/KXI-5IYBdhLWcg3w0MHx - John Y
3
我相信这个问题已经在最近的版本中得到了修复。https://github.com/numpy/numpy/pull/6910 - Robert Kern
3个回答

10

编辑:

针对使用numpy > 1.11.0的Windows系统进行dtype操作:

根据@John Y的建议,可以使用np.random.randint中的命名参数dtype将整数转换为所需格式:

a = np.random.randint(2147483647, 9223372036854775807, size=3, dtype=np.int64)

您可以通过设置randint的范围来直接生成一个数组;这可能比逐个生成和聚合一个数组更有效:

[编辑完毕]

文档字符串:(numpy randint)

randint(low, high=None, size=None)

32位整型的大小范围:

ii32 = np.iinfo(np.int32)
iinfo(min=-2147483648, max=2147483647, dtype=int32)

int64和C语言long类型的大小范围

ii64 =  np.iinfo(np.int64)
iinfo(min=-9223372036854775808, max=9223372036854775807, dtype=int64)

生成一个 int64 类型的数组,其中每个元素的值均大于 int32.max。
a = np.random.randint(2147483647, 9223372036854775807, size = 3)
array([4841796342900989982,   43877033468085758,  205656391264979944])

检查数据类型:返回的结果应为int64

a.dtype
dtype('int64')

numpy.randint提供了在指定范围内的均匀分布(注意,该范围不包括两端,与python的randint函数不同)。


我刚刚尝试了完全相同的操作,但是出现了“high is out of bounds for int32”的错误。我的配置是Windows 7 64位,Python 3.4.3 32位,numpy 1.11.0。 - George Sovetov
嗯...很抱歉我无法帮助你,因为我没有Windows机器,而且我的设置是使用Python 64位。(这可能解释了为什么它可以工作) - Reblochon Masque
我会在 Linux 和 Windows 上的 64 位 Python 上进行检查。 - George Sovetov
1
你可能需要显式指定 dtype 参数到(NumPy的)randint()。在我的系统上,如果我不指定它,我会得到 ValueError: high is out of bounds for int32 的错误。但是 a = np.random.randint(2147483647, 9223372036854775807, size=3, dtype=np.int64) 是有效的。显然,这个参数还没有被包含在官方文档中;这个功能只是最近添加的(我认为是2016年1月)。 - John Y
这是一个很好的建议,John Y。有趣的是,在使用Python 64位版本的Mac OSX上,dtype会抛出TypeError: randint() got an unexpected keyword argument 'dtype'错误。你是在Windows机器上吗?也许这就是NumPy为了克服Windows int32而实施的解决方法。 - Reblochon Masque
是的,我正在使用Windows。我相信dtype参数是1.11.0版本的新功能。 - John Y

6
您可以使用 random.randint 并转换返回值:
>>> import numpy as np
>>> import random
>>> np.int64(random.randint(10000, 1000000000000))
321601597066

我不能保证这是最快的方法,但至少它能够正常工作并且非常清晰...(如果你需要一个数组,只需多次执行此操作即可)。


确实,那应该可以。我得测试一下它的效率如何。 - George Sovetov

6
如Robert Kern在上面的评论中提到的那样,在最新版本的numpy(v1.11.0)中,np.random.randint接受一个dtype=参数,允许您直接生成64位整数。
如果您使用的是旧版本的numpy,并且由于某种原因无法升级,那么您提出的解决方案生成随机字节,将其视为int64并根据所需范围截断它们应该同样有效-事实上,那就是numpy内部RNG的本质。*。
*正如@moarningsun在下面指出的那样,rk_random_uint64实际上使用拒绝抽样,但我仍然认为用模数包装值没有理由不这样做。
import numpy as np
from scipy import stats

def randint64(low, high, size, seed=None):

    # generate a string of random bytes
    n = np.prod(size)
    bytes = np.random.RandomState(seed).bytes(n * 8)

    # view as an int64 array
    ints = np.fromstring(bytes, np.int64, n).reshape(size)

    ints %= np.int64(high - low)    # truncate
    ints += np.int64(low)           # offset

    return ints

imax = np.iinfo(np.int64).max
print(imax)
# 9223372036854775807

ints = randint64(0, imax, int(1E6), seed=0)

print(ints.max())
# 9223355891497906972

# test uniformity
print(stats.kstest(ints, stats.uniform(loc=0, scale=imax).cdf))
# KstestResult(statistic=0.00085961807556278469, pvalue=0.45082598256836681

1
在那个Numpy代码中,超出范围的值被丢弃而不是环绕!我认为注释“如果rng足够大,则数字会环绕”是指无符号加法out[i] = off + val; - user2379410

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接