为什么列表理解比numpy的用于乘以阵列快得多?为什么列表理解比numpy的用于乘以阵列快得多?(W

2019-05-12 05:43发布

最近,我回答到这哪曾想2所列出的乘法问题,一些用户建议使用numpy的下面的方式,沿着我的我认为这是正确的方法:

(a.T*b).T

此外,我发现aray.resize()有这样一个相同的性能。 无论如何另一个答案建议使用列表中理解的解决方案:

[[m*n for n in second] for m, second in zip(b,a)]

但基准后,我看到名单理解的性能比numpy的非常快:

from timeit import timeit

s1="""
a=[[2,3,5],[3,6,2],[1,3,2]]
b=[4,2,1]

[[m*n for n in second] for m, second in zip(b,a)]
"""
s2="""
a=np.array([[2,3,5],[3,6,2],[1,3,2]])
b=np.array([4,2,1])

(a.T*b).T
"""

print ' first: ' ,timeit(stmt=s1, number=1000000)
print 'second : ',timeit(stmt=s2, number=1000000,setup="import numpy as np")

结果:

 first:  1.49778485298
second :  7.43547797203

正如你所看到numpy的大约5倍快。 但最令人惊讶的事情是,它不使用转置,并为下面的代码速度更快:

a=np.array([[2,3,5],[3,6,2],[1,3,2]])
b=np.array([[4],[2],[1]])

a*b 

该列表理解仍然是5时faster.So除了这一点,列表内涵执行用C这里我们使用2嵌套循环和的zip功能,那么可能是什么原因呢? 是不是因为操作*在numpy的?

还要注意的是有没有问题timeit这里我的推杆的import部分setup

我还与大挂毯试了一下,差越低,但仍然没有任何意义:

s1="""
a=[[2,3,5],[3,6,2],[1,3,2]]*10000
b=[4,2,1]*10000

[[m*n for n in second] for m, second in zip(b,a)]
"""
s2="""
a=np.array([[2,3,5],[3,6,2],[1,3,2]]*10000)
b=np.array([4,2,1]*10000)

(a.T*b).T

"""



print ' first: ' ,timeit(stmt=s1, number=1000)
print 'second : ',timeit(stmt=s2, number=1000,setup="import numpy as np")

结果:

 first:  10.7480301857
second :  13.1278889179

Answer 1:

numpy的阵列的创作比创造名单慢得多:

In [153]: %timeit a = [[2,3,5],[3,6,2],[1,3,2]]
1000000 loops, best of 3: 308 ns per loop

In [154]: %timeit a = np.array([[2,3,5],[3,6,2],[1,3,2]])
100000 loops, best of 3: 2.27 µs per loop

通过NumPy的功能发生也可以有固定成本呼叫之前可以通过一个快速底层C / Fortran函数进行计算的肉。 这可以包括确保输入是NumPy的阵列,

这些设置/固定成本也有值得牢记假设NumPy的解决方案固有的速度比纯Python解决方案之前。 当你一旦建立了大型阵列,然后对阵列进行许多快速NumPy的操作NumPy的眼前一亮。 它可能无法超越纯Python如果阵列是小的,因为设置的成本会超过卸载计算以编译的C / Fortran的功能的益处。 对于小数组有根本可能没有足够的计算,使其值得的。


如果增加数组的大小了一下,并移动阵列的创作进入设置,然后NumPy的可能比纯Python快得多:

import numpy as np
from timeit import timeit

N, M = 300, 300

a = np.random.randint(100, size=(N,M))
b = np.random.randint(100, size=(N,))

a2 = a.tolist()
b2 = b.tolist()

s1="""
[[m*n for n in second] for m, second in zip(b2,a2)]
"""

s2 = """
(a.T*b).T
"""

s3 = """
a*b[:,None]
"""

assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], (a.T*b).T)
assert np.allclose([[m*n for n in second] for m, second in zip(b2,a2)], a*b[:,None])

print 's1: {:.4f}'.format(
    timeit(stmt=s1, number=10**3, setup='from __main__ import a2,b2'))
print 's2: {:.4f}'.format(
    timeit(stmt=s2, number=10**3, setup='from __main__ import a,b'))
print 's3: {:.4f}'.format(
    timeit(stmt=s3, number=10**3, setup='from __main__ import a,b'))

产量

s1: 4.6990
s2: 0.1224
s3: 0.1234


文章来源: Why list comprehension is much faster than numpy for multiplying arrays?