有几种方法可以做到这一点,每种方法都有其优点/缺点,以下四种方法就在我的脑海中......
- pythons own
random.sample
,很简单并且是内置的,虽然它可能不是最快的......
numpy.random.permutation
再次简单,但它创建了一个我们必须切片的副本,哎呀!
numpy.random.shuffle
因为它就地洗牌所以速度更快,但我们仍然需要切片。
numpy.random.sample
是最快的,但它只适用于 0 到 1 的区间,所以我们必须对其进行归一化,并将其转换为整数以获得随机索引,最后我们仍然需要切片,注意归一化为我们想要的大小不会生成均匀随机分布。
这里有一些基准。
import timeit
from matplotlib import pyplot as plt
setup = \
"""
import numpy
import random
number_of_members = 20
values = range(50)
"""
number_of_repetitions = 20
array_sizes = (10, 200)
python_random_times = [timeit.timeit(stmt = "[random.sample(values, number_of_members) for index in xrange({0})]".format(array_size),
setup = setup,
number = number_of_repetitions)
for array_size in xrange(*array_sizes)]
numpy_permutation_times = [timeit.timeit(stmt = "[numpy.random.permutation(values)[:number_of_members] for index in xrange({0})]".format(array_size),
setup = setup,
number = number_of_repetitions)
for array_size in xrange(*array_sizes)]
numpy_shuffle_times = [timeit.timeit(stmt = \
"""
random_arrays = []
for index in xrange({0}):
numpy.random.shuffle(values)
random_arrays.append(values[:number_of_members])
""".format(array_size),
setup = setup,
number = number_of_repetitions)
for array_size in xrange(*array_sizes)]
numpy_sample_times = [timeit.timeit(stmt = \
"""
values = numpy.asarray(values)
random_arrays = [values[indices][:number_of_members]
for indices in (numpy.random.sample(({0}, len(values))) * len(values)).astype(int)]
""".format(array_size),
setup = setup,
number = number_of_repetitions)
for array_size in xrange(*array_sizes)]
line_0 = plt.plot(xrange(*array_sizes),
python_random_times,
color = 'black',
label = 'random.sample')
line_1 = plt.plot(xrange(*array_sizes),
numpy_permutation_times,
color = 'red',
label = 'numpy.random.permutations'
)
line_2 = plt.plot(xrange(*array_sizes),
numpy_shuffle_times,
color = 'yellow',
label = 'numpy.shuffle')
line_3 = plt.plot(xrange(*array_sizes),
numpy_sample_times,
color = 'green',
label = 'numpy.random.sample')
plt.xlabel('Number of Arrays')
plt.ylabel('Time in (s) for %i rep' % number_of_repetitions)
plt.title('Different ways to sample.')
plt.legend()
plt.show()
结果:
所以它看起来numpy.random.permutation
是最糟糕的,不足为奇,蟒蛇自己random.sample
拥有它,所以它看起来像是一场激烈的竞争,并且numpy.random.shuffle
逐渐退出,所以任何一个都足够了,即使有更高的内存占用我仍然更喜欢它,因为我真的不需要构建数组我只需要随机索引......numpy.random.sample
numpy.random.sample
numpy.random.sample
$ uname -a
Darwin Kernel Version 10.8.0: Tue Jun 7 16:33:36 PDT 2011; root:xnu-1504.15.3~1/RELEASE_I386 i386
$ python --version
Python 2.6.1
$ python -c "import numpy; print numpy.__version__"
1.6.1
更新
不幸的是numpy.random.sample
,它不会从人群中提取独特的元素,所以你会得到重复,所以坚持使用 shuffle 也一样快。
更新 2
如果您想保留在 numpy 中以利用其一些内置功能,只需将值转换为 numpy 数组。
import numpy as np
values = ['cat', 'popcorn', 'mescaline']
number_of_members = 2
N = 1000000
random_arrays = np.asarray([values] * N)
_ = [np.random.shuffle(array) for array in random_arrays]
subset = random_arrays[:, :number_of_members]
请注意,这里的 N 非常大,因此您将获得重复数量的排列,排列我的意思是值的顺序而不是排列中的重复值,因为从根本上说,如果只是计算,任何给定的有限集合上都有有限数量的排列整个集合然后它的 n!,如果只选择 k 个元素它的 n!/(n - k)! 即使不是这种情况,这意味着我们的集合要大得多,我们仍然可能会根据随机函数实现得到重复,因为 shuffle/permutation/... 等等只适用于当前集合并且不知道在人口中,这可能会或可能不会被接受,这取决于您要实现的目标,如果您想要一组独特的排列,那么您将生成该组并对其进行二次抽样。