快速总结numpy数组元素

时间:2013-12-17 17:08:09

标签: python optimization numpy

让我们说我想做一个numpy数组列表的元素总和:

tosum = [rand(100,100) for n in range(10)]

我一直在寻找最佳方法。好像numpy.sum很糟糕:

timeit.timeit('sum(array(tosum), axis=0)',
              setup='from numpy import sum; from __main__ import tosum, array',
              number=10000)
75.02289700508118
timeit.timeit('sum(tosum, axis=0)',
              setup='from numpy import sum; from __main__ import tosum',
              number=10000)
78.99106407165527

减少速度要快得多(接近两个数量级):

timeit.timeit('reduce(add,tosum)',
              setup='from numpy import add; from __main__ import tosum',
              number=10000)
1.131795883178711

看起来reduce甚至对非numpy总和有一个有意义的领先(注意这些是1e6运行而不是1e4以上的时间):

timeit.timeit('reduce(add,tosum)',
              setup='from numpy import add; from __main__ import tosum',
              number=1000000)
109.98814797401428

timeit.timeit('sum(tosum)',
              setup='from __main__ import tosum',
              number=1000000)
125.52461504936218

我应该尝试其他方法吗?任何人都可以解释排名吗?


修改

如果首先将列表转换为numpy数组,那么

numpy.sum肯定会更快:

tosum2 = array(tosum)
timeit.timeit('sum(tosum2, axis=0)',
              setup='from numpy import sum; from __main__ import tosum2',
              number=10000)
1.1545608043670654

但是,我只对做一次总和感兴趣,所以将数组转换为numpy数组仍然会导致真正的性能损失。

2 个答案:

答案 0 :(得分:5)

以下内容与reduce具有竞争力,如果tosum列表足够长,则速度更快。但是,它不是很多更快,而且代码更多。 (reduce(add, tosum)肯定很漂亮。)

def loop_inplace_sum(arrlist):
    # assumes len(arrlist) > 0
    sum = arrlist[0].copy()
    for a in arrlist[1:]:
        sum += a
    return sum

原始tosum的时间安排。 reduce(add, tosum)速度更快:

In [128]: tosum = [rand(100,100) for n in range(10)]

In [129]: %timeit reduce(add, tosum)
10000 loops, best of 3: 73.5 µs per loop

In [130]: %timeit loop_inplace_sum(tosum)
10000 loops, best of 3: 78 µs per loop

更长阵列列表的时间安排。现在loop_inplace_sum更快。

In [131]: tosum = [rand(100,100) for n in range(500)]

In [132]: %timeit reduce(add, tosum)
100 loops, best of 3: 5.09 ms per loop

In [133]: %timeit loop_inplace_sum(tosum)
100 loops, best of 3: 4.4 ms per loop

答案 1 :(得分:1)

Numpy sum 并不可怕,您只是在以错误的方式使用 numpy。如果将普通的 Python、函数(包括 reduce!)、循环和列表与 numpy 数组结合使用,您将无法利用 numpy 的速度优势。如果你希望你的代码运行得很快,你必须只使用 numpy

由于您没有在代码片段中指定任何导入,我不确定函数 randn 在做什么或它来自哪里,所以我只是假设 tosum 应该只代表一个列表一些随机数的 10 个矩阵。以下代码片段表明 numpy 绝对没有您声称的那么慢:

import numpy as np
import timeit

def test_np_sum(n=10):
    # n represents the numbers of matrices to sum up element wise
    tosum = np.random.randint(0, 100, size=(n, 10, 10)) # n 10x10 matrices, shape = (n, 10, 10)
    summed = np.sum(tosum, axis=0) # shape = (10, 10)

然后测试它:

timeit.timeit('test_np_sum()', number=10000, setup='from __main__ import test_np_sum')

0.8418250999999941