【发布时间】:2017-04-16 08:10:04
【问题描述】:
我需要一种无需替换某个数组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)
【问题讨论】:
-
我明白了,这是一个长期存在的问题。请@ayhan,您能否根据您的评论做出回答,以便我将其标记为已接受?
-
我知道这个问题,因为它在这里出现了几次,但老实说,我不知道为什么它变慢的细节。我的回答是一个链接和一些引号,但最好等待其他人也许他们可以解释这个问题?
-
我认为问题在于
np.random.choice通过生成数组中 所有 索引的排列,然后取第一个n_sample这些(见this line)。如果n_sample远小于数组a中的元素数量,这将变得非常低效。 -
另一方面,
random.sample只抽取n_samples随机样本。它通过以下两种方式之一执行此操作 - 要么跟踪它已经选择的项目(如果n_samples << N),要么通过维护一个可以选择的候选项目的缩小池(如果n_samples与 @ 相比相对较大) 987654339@)。你可以看到源代码here - 它非常简单易读。