numpy中的非重复随机数


88

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

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

“非重复”是什么意思?随机数序列永远不会重复出现吗?这是不可能的,因为随机数发生器的状态需要适合计算机的有限存储器。还是说没有一个数字出现两次?
斯文·马纳赫

5
非重复意味着您有一个没有重复的列表。
多项式

2
也许您需要一个随机排列?docs.scipy.org/doc/numpy/reference/generation / ...
cyborg

Answers:


106

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,没有GeneratorAPI,则可以random.sample()从标准库中使用:

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

您也可以使用numpy.random.shuffle()和切片,但这会降低效率:

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

replace在遗留numpy.random.choice函数中也有一个参数,但是由于随机数流的稳定性保证,该参数的实现效率低下,然后变得效率低下,因此不建议使用它。(它基本上是在内部执行随机播放和切片操作。)


1
打印random.sample(range(20),10)在python 2.6上不起作用?!
学术界

import random
Sven Marnach 2011年

问题是由于Pydev配置错误。Thks
Academia

1
如果我的n不是20,而是1000000,但是我只需要10个唯一数字,该怎么办呢?
mrgloom

2
@mrgloom在Python 3中,random.sample(range(n), 10))即使对于非常大nrange对象也将非常有效,因为对象只是存储开始,结束和步长值的小包装,而不会创建整数的完整列表。在Python 2中,您可以替换rangexrange以获得类似的行为。
斯文·马纳赫

107

我认为numpy.random.sample现在不行。这是我的方式:

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

25
代替range(n)(或arange(n))作为第一个参数choice,它等效于just pass n,例如choice(20, 10, replace=False)
乔什·波德

1
请注意,这np.random.choice(a, size, replace=False)对于大型a计算机来说非常慢-在我的机器上,对于1M大约30毫秒。
马修·拉兹

3
为了避免大量n使用的时间和内存问题numpy.random.Generator.choice(从numpy v1.17开始)
benbo

1
我看到的主要缺点是np.random.choice没有轴参数->仅用于一维数组。
Moosefeather

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人士戴上帽子。


1

您也可以通过排序获得此信息:

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

-3

只需生成一个包含所需数字范围的数组,然后通过将一个随机数与该数组中的第0个元素重复交换就可以对它们进行混洗。这将产生一个不包含重复值的随机序列。


2
所得随机序列的另一个特性是它不是特别随机
Sven Marnach 2011年

@SvenMarnach-不过,对于大多数用途来说,它足够随机。如果他希望随机性更高,可以使用双随机方法。
多项式

这是没有意义的。OP可以使用库调用来正确执行。它们比自定义版本更易于使用,运行更快并且更具可读性。我想不出任何理由在这里使用错误的算法,只是因为使用正确的算法没有任何缺点时,它可能“足够随机”。
Sven Marnach 2011年

@SvenMarnach-足够公平。我不知道numpy,所以我只是提供了一个潜在的解决方案。
多项式
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.