Python 为什么random.sample比numpy';什么是随机选择?
我需要一种无需更换特定数组的方法Python 为什么random.sample比numpy';什么是随机选择?,python,numpy,random,Python,Numpy,Random,我需要一种无需更换特定数组的方法a。我尝试了两种方法(参见下面的MCVE),使用random.sample()和np.random.choice 我假设numpy函数会更快,但事实并非如此。在我的测试中,random.sample比np.random.choice快约15% 这是正确的,还是我在下面的例子中做错了什么?如果这是正确的,为什么 import numpy as np import random import time from contextlib import contextman
a
。我尝试了两种方法(参见下面的MCVE),使用random.sample()
和np.random.choice
我假设numpy
函数会更快,但事实并非如此。在我的测试中,random.sample
比np.random.choice
快约15%
这是正确的,还是我在下面的例子中做错了什么?如果这是正确的,为什么
import numpy as np
import random
import time
from contextlib import contextmanager
@contextmanager
def timeblock(label):
start = time.clock()
try:
yield
finally:
end = time.clock()
print ('{} elapsed: {}'.format(label, end - start))
def f1(a, n_sample):
return random.sample(range(len(a)), n_sample)
def f2(a, n_sample):
return np.random.choice(len(a), n_sample, replace=False)
# Generate random array
a = np.random.uniform(1., 100., 10000)
# Number of samples' indexes to randomly take from a
n_sample = 100
# Number of times to repeat functions f1 and f2
N = 100000
with timeblock("random.sample"):
for _ in range(N):
f1(a, n_sample)
with timeblock("np.random.choice"):
for _ in range(N):
f2(a, n_sample)
TL;DR自numpy v1.17.0以来,建议使用
numpy.random.default\rng()
对象,而不是numpy.random
。供选择:
将numpy导入为np
rng=np.random.default_rng()#您可以传递种子
rng.choice(…)#接口相同
除了v1.17中引入的随机API的其他更改之外,这个新版本的choice现在更加智能,在大多数情况下应该是最快的。为了向后兼容,旧版本保持不变
正如评论中所提到的,numpy长期存在一个关于
np.random.choice
实现对k无效的问题。我明白了,这是一个长期存在的问题。请@ayhan回复你的评论,这样我就可以把它标记为接受了。我知道这个问题,因为它在这里出现过几次,但我真的不知道为什么它会慢一些。我的答案可能是一个链接和一些引号,但最好是等待其他人,也许他们可以解释这个问题?我认为问题在于,np.random.choice
通过生成数组中所有索引的排列,然后获取其中的第一个n_样本
,进行随机采样而不进行替换(请参阅)。如果n_sample
远小于数组a
中的元素数,则这将变得非常低效。另一方面,random.sample
仅绘制n_samples
随机样本。它通过两种方式之一实现这一点——或者通过跟踪它已经选择的项目(如果n_样本
random.sample elapsed: 0.8711776689742692
np.random.choice elapsed: 1.9704092079773545
np.random.default_rng().choice elapsed: 0.818919860990718
random.sample elapsed: 8.785315042012371
np.random.choice elapsed: 1.9777243090211414
np.random.default_rng().choice elapsed: 1.05490942299366
random.sample elapsed: 80.15063399000792
np.random.choice elapsed: 2.0218082449864596
np.random.default_rng().choice elapsed: 2.8596064270241186
import numpy as np
import random
from timeit import default_timer as timer
from contextlib import contextmanager
@contextmanager
def timeblock(label):
start = timer()
try:
yield
finally:
end = timer()
print ('{} elapsed: {}'.format(label, end - start))
def f1(a, n_sample):
return random.sample(range(len(a)), n_sample)
def f2(a, n_sample):
return np.random.choice(len(a), n_sample, replace=False)
def f3(a, n_sample):
return np.random.default_rng().choice(len(a), n_sample, replace=False)
# Generate random array
a = np.random.uniform(1., 100., 10000)
# Number of samples' indexes to randomly take from a
n_sample = 100
# Number of times to repeat tested functions
N = 100000
print(f'{N} times {n_sample} samples')
with timeblock("random.sample"):
for _ in range(N):
f1(a, n_sample)
with timeblock("np.random.choice"):
for _ in range(N):
f2(a, n_sample)
with timeblock("np.random.default_rng().choice"):
for _ in range(N):
f3(a, n_sample)