一些用户建议使用numpy的以下方法,以及我认为是正确的方法:
(a.T*b).T
我也发现aray.resize()具有相同的性能。无论如何,另一个答案建议使用列表理解的解决方案:
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倍。因此,除了这一点之外,这里的列表理解是在C语言中执行的,我们使用了2个嵌套循环和一个zip函数,那又是什么原因呢?是因为*在numpy中进行操作吗?
zip
*
另请注意,在timeit这里放置import零件没有问题setup。
timeit
import
setup
我还尝试了更大的arras,差异变小了,但还是没有道理:
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
创建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
在可以通过快速的基础C / Fortran函数执行计算之前,NumPy函数调用还可能导致固定费用。这可以包括确保输入为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