[英]how to speed up enumerate for numpy array / how to enumerate over numpy array efficiently?
我需要生成很多随机数。 我尝试过使用random.random
但这个功能很慢。 因此我切换到numpy.random.random
,这更快! 到现在为止还挺好。 生成的随机数实际上用于计算某些事物(基于数字)。 因此,我enumerate
每个数字并替换值。 这似乎杀死了我之前获得的所有加速。 以下是使用timeit()
生成的统计信息:
test_random - no enumerate
0.133111953735
test_np_random - no enumerate
0.0177130699158
test_random - enumerate
0.269361019135
test_np_random - enumerate
1.22525310516
正如您所看到的,使用numpy生成数字的速度几乎要快10倍,但枚举这些数字会让我的运行时间相等。
下面是我正在使用的代码:
import numpy as np
import timeit
import random
NBR_TIMES = 10
NBR_ELEMENTS = 100000
def test_random(do_enumerate=False):
y = [random.random() for i in range(NBR_ELEMENTS)]
if do_enumerate:
for index, item in enumerate(y):
# overwrite the y value, in reality this will be some function of 'item'
y[index] = 1 + item
def test_np_random(do_enumerate=False):
y = np.random.random(NBR_ELEMENTS)
if do_enumerate:
for index, item in enumerate(y):
# overwrite the y value, in reality this will be some function of 'item'
y[index] = 1 + item
if __name__ == '__main__':
from timeit import Timer
t = Timer("test_random()", "from __main__ import test_random")
print "test_random - no enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_np_random()", "from __main__ import test_np_random")
print "test_np_random - no enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_random(True)", "from __main__ import test_random")
print "test_random - enumerate"
print t.timeit(NBR_TIMES)
t = Timer("test_np_random(True)", "from __main__ import test_np_random")
print "test_np_random - enumerate"
print t.timeit(NBR_TIMES)
什么是加快这一速度的最佳方法,为什么如此大幅度地enumerate
缓慢的事情?
编辑:我使用enumerate
的原因是因为我需要索引和当前元素的值。
要充分利用numpy的速度,您希望尽可能创建ufunc 。 将vectorize
应用于函数就像mgibsonbr所建议的那样是一种方法,但是如果可能的话,更好的方法就是构造一个利用numpy的内置ufuncs的函数。 所以像这样:
>>> import numpy
>>> a = numpy.random.random(10)
>>> a + 1
array([ 1.29738145, 1.33004628, 1.45825441, 1.46171177, 1.56863326,
1.58502855, 1.06693054, 1.93304272, 1.66056379, 1.91418473])
>>> (a + 1) * 0.25 / 4
array([ 0.08108634, 0.08312789, 0.0911409 , 0.09135699, 0.09803958,
0.09906428, 0.06668316, 0.12081517, 0.10378524, 0.11963655])
要在numpy数组中应用的函数的性质是什么? 如果你告诉我们,也许我们可以帮你提出一个只使用numpy ufuncs的版本。
也可以在不使用enumerate
情况下生成索引数组。 Numpy提供了ndenumerate
,它是一个迭代器,可能更慢,但它也提供了indices
,这是一种非常快速的方法来生成与数组中的值对应的索引。 所以...
>>> numpy.indices(a.shape)
array([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
所以更明确一点,你可以使用上面的内容并使用numpy.rec.fromarrays
将它们组合起来:
>>> a = numpy.random.random(10)
>>> ind = numpy.indices(a.shape)
>>> numpy.rec.fromarrays([ind[0], a])
rec.array([(0, 0.092473494150913438), (1, 0.20853257641948986),
(2, 0.35141455604686067), (3, 0.12212258656960817),
(4, 0.50986868372639049), (5, 0.0011439325711705139),
(6, 0.50412473457942508), (7, 0.28973489788728601),
(8, 0.20078799423168536), (9, 0.34527678271856999)],
dtype=[('f0', '<i8'), ('f1', '<f8')])
它开始听起来像你主要担心的是就地执行操作。 使用vectorize
更难做到,但使用ufunc方法很容易:
>>> def somefunc(a):
... a += 1
... a /= 15
...
>>> a = numpy.random.random(10)
>>> b = a
>>> somefunc(a)
>>> a
array([ 0.07158446, 0.07052393, 0.07276768, 0.09813235, 0.09429439,
0.08561703, 0.11204622, 0.10773558, 0.11878885, 0.10969279])
>>> b
array([ 0.07158446, 0.07052393, 0.07276768, 0.09813235, 0.09429439,
0.08561703, 0.11204622, 0.10773558, 0.11878885, 0.10969279])
如您所见,numpy就地执行这些操作。
检查numpy.vectorize ,它应该允许你将任意函数应用于numpy数组。 对于您的简单示例,您可以执行以下操作:
vecFunc = vectorize(lambda x: x + 1)
vecFunc(y)
但是,这将创建一个新的numpy数组,而不是就地修改它(在您的特定情况下可能是也可能不是问题)。
一般来说,使用numpy函数操作numpy结构总是比使用python函数迭代更好,因为前者不仅被优化而是用C实现,而后者总是被解释。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.