当前位置: 首页 > 面试题库 >

为什么列表理解比数组乘以numpy要快得多?

司马辉
2023-03-14
问题内容

一些用户建议使用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倍。因此,除了这一点之外,这里的列表理解是在C语言中执行的,我们使用了2个嵌套循环和一个zip函数,那又是什么原因呢?是因为*在numpy中进行操作吗?

另请注意,在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


 类似资料:
  • 我想知道为什么列表理解比附加在列表上要快得多。我以为区别只是表达,但事实并非如此。 列表理解速度提高了50%。为什么?

  • 我们正在使用定制的Spring数据AuditAware来将审计数据保存在我们的表中。最近我们正在构建一个新的微服务,我们想探索其他替代解决方案。我们发现Javers是一个潜在的合适人选。 与spring boot的集成是无缝的,审计工作做得很好。但一个问题是在jv_快照表中,pk序列乘以100。我已经看过源代码了,这是特意为这个表添加的。有什么特别的理由这样做吗?我担心的是,我们需要大量的数据,如

  • 问题内容: 我不知道为什么numba在这里击败numpy(超过3倍)。我在这里进行基准测试时是否犯了一些根本性的错误?对于numpy来说似乎是完美的情况,不是吗?请注意,作为检查,我还运行了一个结合了numba和numpy的变体(未显示),正如预期的那样,它与不带numba的numpy运行相同。 (顺便说一下,这是一个后续问题:数字处理二维数组的最快方法:dataframe vs series v

  • 问题内容: 当我遇到性能问题时,我只是更改了一个正在编写的程序,以将数据存储为numpy数组,而两者之间的区别令人难以置信。最初耗时30分钟,而现在耗时2.5秒! 我想知道它是如何做到的。我认为这是因为它消除了对循环的需要,但除此之外,我感到很困惑。 问题答案: 块状阵列是均质类型的密集堆积阵列。相比之下,Python列表是指向对象的指针数组,即使它们都属于同一类型。因此,您可以获得引用局部性的好

  • 问题内容: 因此,我没有讲一个很长的故事,而是在编写一些代码,即从二进制文件中读取一些数据,然后使用for循环遍历每个点。因此,我完成了代码,运行速度非常慢。我从约128个数据通道中遍历了约60,000个点,这需要一分钟或更长时间来处理。这比我预期的Python运行速度要慢得多。因此,我通过使用Numpy使整个事情变得更加高效,但是在试图弄清为什么原始进程运行如此缓慢的过程中,我们进行了一些类型检

  • 问题内容: 我刚刚读过“深入Python”,“元组比列表快”。 元组是不可变的,列表是可变的,但是我不太明白为什么元组更快。 有人对此进行过性能测试吗? 问题答案: 所报告的“构建速度”比率仅适用于 常量 元组(其项目由文字表示的元组)。仔细观察(并在您的机器上重复-您只需要在shell /命令窗口中键入命令即可!)…: 我没有在3.0上进行测量,因为我当然没有它-它已经完全过时了,绝对没有理由保