为什么Numpy.array比用于获取子列表的内置列表慢

时间:2015-04-23 04:51:07

标签: python performance python-2.7 numpy

我将改进我的代码片段的性能,这将经常递归地获取子数组。

所以我使用了numpy.array而不是内置列表。因为,据我所知,在获取子数组时,numpy.array不会复制原始列表。

但是当我改为numpy.array时,表现变得更糟。所以我想知道原因。谢谢!

以下是我的代码片段和使用我得到的不同对象的执行时间:

import timeit
stat = ''' 
import numpy
def func(a):
    a[len(a)-1] += 1
    if len(a) == 1:
        return a[0]
    else:
        return func(a[1:len(a)])
a1=[1,2,3,4,5,6,7,8,9,10]
a2=numpy.array([1,2,3,4,5,6,7,8,9,10])
'''
if __name__ == "__main__":
    print "Execution time with build-in list: {0}".format(timeit.timeit('func(a1)', setup = stat, number = 1000))
    print "Execution time with Numpy array: {0}".format(timeit.timeit('func(a2)', setup = stat, number = 1000))

在我的64位mac(Python 2.7.6 + Numpy 1.8.0rc1)上,输出为:

Execution time with build-in list: 0.00507998466492
Execution time with Numpy array: 0.0195469856262

2 个答案:

答案 0 :(得分:1)

如果修改最后两行代码,您将获得相同的执行时间,如下所示:

print "Execution time with build-in list: {0}".format(timeit.timeit(
    'func(a1)', setup = stat, number = 1000), 'gc.enable()')
print "Execution time with Numpy array:   {0}".format(timeit.timeit(
    'func(a2)', setup = stat, number = 1000), 'gc.enable()')

在这两种情况下,我们允许 timeit 打开所谓的垃圾收集,即在不再使用时释放内存的过程。上述修改返回,例如:

Execution time with build-in list: 0.00580596923828
Execution time with Numpy array:   0.00822710990906

具有相同的数量级。根据 timeit "的文档,默认情况下,它会暂时关闭垃圾收集。这种方法的优点在于它使独立时序更具可比性。这个缺点是垃圾收集可能是所测量功能性能的重要组成部分。"

应该使用什么方法,即使用或不使用垃圾收集,何时使用。另请注意,如果从时间模块应用time.time()块,您将获得更长的时间。

答案 1 :(得分:0)

感谢所有人'对于这个问题的答案和评论,你已经向我展示了有价值的信息来做出这个答案。

答案是这样的。在我的问题中导致numpy数组性能不佳的原因是访问单个项目并在numpy数组上分配内置类型比内置列表慢。实际上,存在获取numpy数组的子数组比内置列表的性能增益。但是在短阵列中增益太小,例如在我的例子中,len = 10的数组,所以丢失的小增益被这一行所取代:a[len(a)-1] += 1我们在其中访问了单个项目并在内置类型int之间进行转换。

以下代码证明了原因:

import numpy
from timeit import timeit
stat = ''' 
import numpy
a1 = range(4000)
a2 = numpy.array(a1)
i = 0
'''
if __name__ == "__main__":
    test_times = 1000
    print '1. {0:.8f}'.format(timeit('a1[i]', setup = stat, number = test_times))
    print '2. {0:.8f}'.format(timeit('a2[i]', setup = stat, number = test_times))
    print '3. {0:.8f}'.format(timeit('i += a1[i]; ++i', setup = stat, number = test_times))
    print '4. {0:.8f}'.format(timeit('i += a2[i]; ++i', setup = stat, number = test_times))
    print '5. {0:.8f}'.format(timeit('a = a1[i:len(a1)]; ++i', setup = stat, number = test_times))
    print '6. {0:.8f}'.format(timeit('a = a2[i:len(a2)]; ++i', setup = stat, number = test_times))

我的mac中的运行结果如下:

1. 0.00005913
2. 0.00017881
3. 0.00008607
4. 0.00084305
5. 0.01492000
6. 0.00053406

我们可以从上面的结果中得到这些:

  1. 1 vs 2 :访问单个项目时,Numpy数组比内置列表慢。
  2. 2 vs 4 :当将numpy数组中的项目数据分配给内置类型(int)时,似乎需要花费额外时间的数据转换。对于内置列表,花费的时间很少。
  3. 5 vs 6 :与内置列表相比,Numpy在获取子数组时确实节省了很多时间。