使用列表中的随机元素创建 numpy 数组
Posted
技术标签:
【中文标题】使用列表中的随机元素创建 numpy 数组【英文标题】:Create numpy array with random elements from list 【发布时间】:2012-10-31 09:16:24 【问题描述】:有没有一种有效的方法来创建一个任意长的 numpy 数组,其中每个维度由从长度 >= n 的列表中提取的 n 个元素组成?列表中的每个元素每个维度只能绘制一次。
例如,如果我有 l = ['cat', 'mescaline', 'popcorn']
列表,我希望能够(例如通过键入 np.random.pick_random(l, (3, 2), replace=false)
之类的内容)创建一个数组 array([['cat', 'popcorn'], ['cat', 'popcorn'], ['mescaline', 'cat']])
。
谢谢。
【问题讨论】:
脏东西简单明显的导入随机是不是有问题; random.shuffle()? 我想知道为什么它必须是numpy
?一般来说,numpy 用于数值类型的计算,因此它的名称是数值 python 的缩写,当然它确实支持其他类型...... python 自己的 random.sample
可能更适合这个 [random.sample(['cat', 'mescaline', 'popcorn'], number_of_members) for index in xrange(number_of_arrays)]
...
@samy-vilar 原因是我想避免慢循环。我将把它用于蒙特卡洛模拟,所以我需要相当大的数组。
@jim-dennis 创建大型数组时的性能差异。
【参考方案1】:
有几种方法可以做到这一点,每种方法都有其优点/缺点,以下四种只是 从我的头顶...
pythons 自己的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
没有从群体中提取独特元素,所以你会得到重复,所以坚持随机播放也一样快。
更新 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/... 等等仅适用于当前集合并且不知道总体而言,这可能会也可能不会接受,这取决于您要达到的目标,如果您想要一组独特的排列,那么您将生成该组并对其进行二次抽样。
【讨论】:
感谢您的努力。 numpy.shuffle 方法的效率还可以。但是,在对数组进行计算时,它并没有使我免于慢循环。例如,我想做 sum(random_arrays, axis=1)。抱歉,我不清楚我在寻找什么。 嗯 random_arrays.sum(axis = 1)? random_arrays 应该是一个 numpy 类型。另请注意,shuffle 可能会根据您需要的随机数组的数量生成非唯一的排列,如果您真的想要唯一的排列而不是您必须手动生成它们并对其进行子采样,还请注意numpy.random.choice
已添加到1.7 我目前在 1.6.1,docs.scipy.org/doc/numpy-dev/reference/generated/… 我不确定它的性能需要测试它,但它可能会更慢,因为它会生成新的数组...
也许我理解错了,但我这样做的方式会生成一个“列表”:pastee.org/d76bb 排列不应该是唯一的。
@Aae 我已经更新为使用 numpy,sum 也只能应用于数值,这里有字符串值,如果你想使用索引,只需将值替换为 range(leng(values))
和它应该可以工作。【参考方案2】:
这是一种使用 numpy 的 np.random.randint
的方法:
In [68]: l = np.array(['cat', 'mescaline', 'popcorn'])
In [69]: l[np.random.randint(len(l), size=(3,2))]
Out[69]:
array([['cat', 'popcorn'],
['popcorn', 'popcorn'],
['mescaline', 'cat']],
dtype='|S9')
编辑:在每个元素在每一行中最多出现一次的附加细节之后
这不是很节省空间,您需要更好的东西吗?
In [29]: l = np.array(['cat', 'mescaline', 'popcorn'])
In [30]: array([np.random.choice(l, 3, replace=False) for i in xrange(5)])
Out[30]:
array([['mescaline', 'popcorn', 'cat'],
['mescaline', 'popcorn', 'cat'],
['popcorn', 'mescaline', 'cat'],
['mescaline', 'cat', 'popcorn'],
['mescaline', 'cat', 'popcorn']],
dtype='|S9')
【讨论】:
谢谢你。但是,有一个细节我忘了提。新数组不应包含多次包含相同元素的维度(如果它没有在列表中多次列出)。 更新提供了预期的结果,但效率不高。效率确实是我所要求的。对不起,如果我不清楚。 @Aae 那么您应该指定哪种类型的效率对您很重要。速度?内存? 速度很重要。我在上面的评论中提到了它(“避免慢循环”),但我想我可以说得更清楚。【参考方案3】:>>> import numpy
>>> l = numpy.array(['cat', 'mescaline', 'popcorn'])
>>> l[numpy.random.randint(0, len(l), (3, 2))]
array([['popcorn', 'mescaline'],
['mescaline', 'popcorn'],
['cat', 'cat']],
dtype='|S9')
【讨论】:
谢谢。但正如我在这里对另一个人所说的:有一个细节我忘了提。新数组不应包含多次包含相同元素的维度(如果它没有在列表中多次列出)。以上是关于使用列表中的随机元素创建 numpy 数组的主要内容,如果未能解决你的问题,请参考以下文章
数据分析2 numpy(ndarray数组,属性,创建,索引切片,运算,函数,随机数), Pandas(Series创建,缺失值处理,特性,索引,DataFrame)
numpy 从索引列表创建 2D 掩码 [+ 然后从掩码数组中绘制]