numpy中的非重复随机数

Posted

技术标签:

【中文标题】numpy中的非重复随机数【英文标题】:Non-repetitive random number in numpy 【发布时间】:2012-01-20 07:07:08 【问题描述】:

如何在 numpy 中生成不重复的随机数?

list = np.random.random_integers(20,size=(10))

【问题讨论】:

“不重复”是什么意思?随机数序列永远不会重复?这是不可能的,因为随机数生成器的状态需要适应计算机的有限内存。或者你的意思是没有一个数字出现两次? 非重复意味着你有一个没有重复的列表。 也许你需要一个随机排列? docs.scipy.org/doc/numpy/reference/generated/… 【参考方案1】:

numpy.random.Generator.choice 提供了一个 replace 参数来采样,无需替换:

from numpy.random import default_rng

rng = default_rng()
numbers = rng.choice(20, size=10, replace=False)

如果您使用的是 1.17 之前的 NumPy,没有 Generator API,您可以使用标准库中的 random.sample()

print(random.sample(range(20), 10))

你也可以使用numpy.random.shuffle()和slicing,但是这样效率会降低:

a = numpy.arange(20)
numpy.random.shuffle(a)
print a[:10]

在旧的numpy.random.choice 函数中还有一个replace 参数,但是由于随机数流稳定性保证,此参数的实现效率低下,因此效率低下,因此不建议使用它。 (它基本上在内部进行洗牌和切片。)

一些时间安排:

import timeit
print("when output size/k is large, np.random.default_rng().choice() is far far quicker, even when including time taken to create np.random.default_rng()")
print(1, timeit.timeit("rng.choice(a=10**5, size=10**4, replace=False, shuffle=False)", setup="import numpy as np; rng=np.random.default_rng()", number=10**3)) #0.16003450006246567
print(2, timeit.timeit("np.random.default_rng().choice(a=10**5, size=10**4, replace=False, shuffle=False)", setup="import numpy as np", number=10**3)) #0.19915290002245456

print(3, timeit.timeit("random.sample( population=range(10**5), k=10**4)", setup="import random", number=10**3))   #5.115292700007558

print("when output size/k is very small, random.sample() is quicker")
print(4, timeit.timeit("rng.choice(a=10**5, size=10**1, replace=False, shuffle=False)", setup="import numpy as np; rng=np.random.default_rng()", number=10**3))  #0.01609779999125749
print(5, timeit.timeit("random.sample( population=range(10**5), k=10**1)", setup="import random", number=10**3))  #0.008387799956835806

所以numpy.random.Generator.choice 是您通常想要的,除了非常小的输出大小/k

【讨论】:

print random.sample(range(20), 10) 不适用于 python 2.6?! 问题是由于 Pydev 配置错误造成的。谢谢 如果我的 n 不是 20,而是像 1000000,但我只需要其中的 10 个唯一数字,是否有更节省内存的方法? @mrgloom 在 Python 3 中,random.sample(range(n), 10)) 即使对于非常大的n 也会很有效,因为range 对象只是一个存储开始、停止和步进值的小包装器,但不会创建整数的完整列表。在 Python 2 中,您可以将 range 替换为 xrange 以获得类似的行为。【参考方案2】:

我认为numpy.random.sample 现在不能正常工作。这是我的方式:

import numpy as np
np.random.choice(range(20), 10, replace=False)

【讨论】:

而不是range(n)(或arange(n))作为choice的第一个参数,相当于只传递n,例如choice(20, 10, replace=False). 请注意,np.random.choice(a, size, replace=False) 对于大型 a 来说非常慢 - 在我的机器上,a=1M 大约需要 30 毫秒。 为了避免非常大的n 出现时间和内存问题,请使用numpy.random.Generator.choice(从 numpy v1.17 开始) 我看到的主要缺点是 np.random.choice 没有轴参数 -> 它仅适用于一维数组。【参考方案3】:

几年后,有些时候从 10000^2 中选择 40000 (Numpy 1.8.1,imac 2.7 GHz):

import random
import numpy as np

n = 10000
k = 4
np.random.seed( 0 )

%timeit np.random.choice( n**2, k * n, replace=True )  # 536 µs ± 1.58 µs
%timeit np.random.choice( n**2, k * n, replace=False ) # 6.1 s ± 9.91 ms

# https://docs.scipy.org/doc/numpy/reference/random/index.html
randomstate = np.random.default_rng( 0 )
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=False )  # 766 µs ± 2.18 µs
%timeit randomstate.choice( n**2, k * n, replace=False, shuffle=True )   # 1.05 ms ± 1.41 µs

%timeit random.sample( range( n**2 ), k * n )          # 47.3 ms ± 134 µs

(为什么要从 10000^2 中选择 40000 ? 生成大 scipy.sparse.random 矩阵——scipy 1.4.1 使用np.random.choice( replace=False ),slooooow。)

向 numpy.random 人致敬。

【讨论】:

【参考方案4】:

你也可以通过排序得到这个:

random_numbers = np.random.random([num_samples, max_int])
samples = np.argsort(random_numbers, axis=1)

【讨论】:

【参考方案5】:

可以使用 Python 设置列表转换。 0到20之间的10个随机不重复数可以得到:

import random
numbers=set()
while(len(numbers)<10):
    numbers.add(random.randint(0,20))

numbers=list(numbers)
random.shuffle(numbers)
print(numbers)

【讨论】:

【参考方案6】:

只需生成一个包含所需数字范围的数组,然后通过重复将随机数字与数组中的第 0 个元素交换来打乱它们。这会产生一个不包含重复值的随机序列。

【讨论】:

生成的随机序列的另一个属性是it is not particularly random。 @SvenMarnach - 不过,对于大多数目的来说,它是随机的。如果他想要更随机,他可以使用双随机方法。 这毫无意义。 OP 可以使用库调用来做到这一点。它们比自定义版本更易于使用、运行更快且更具可读性。我想不出任何理由为什么我应该在这里使用错误的算法,因为它可能“足够随机”,而使用正确的算法没有任何缺点。 @SvenMarnach - 很公平。我不知道 numpy,所以我只是提供了一个潜在的解决方案。

以上是关于numpy中的非重复随机数的主要内容,如果未能解决你的问题,请参考以下文章

生成带有条件的随机数列表 - numpy [重复]

numpy随机索引 不重复

使用Marklogic(XQuery)中的时间戳生成非重复随机数?

python基础2:随机数生成—random模块、numpy中的random函数

使用numpy产生随机数

python 与Numpy在python中的随机数