繁体   English   中英

如何加快numpy数组的枚举/如何有效地枚举numpy数组?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM