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中的非重复随机数的主要内容,如果未能解决你的问题,请参考以下文章
使用Marklogic(XQuery)中的时间戳生成非重复随机数?