为什么对于2D数组乘法来说for循环比numpy更快

cme*_*ren 5 python for-loop numpy

考虑以下两个函数,它们基本上将小序列中的每个数字与较大序列中的每个数字相乘以构建2D数组,然后将数组中的所有值加倍.noloop()使用2D numpy数组的直接乘法并返回结果,而loop()使用for循环迭代arr1并逐渐构建输出数组.

import numpy as np

arr1 = np.random.rand(100, 1)
arr2 = np.random.rand(1, 100000)

def noloop():
    return (arr1*arr2)*2

def loop():
    out = np.empty((arr1.size, arr2.size))
    for i in range(arr1.size):
        tmp = (arr1[i]*arr2)*2
        out[i] = tmp.reshape(tmp.size)
    return out
Run Code Online (Sandbox Code Playgroud)

我希望noloop即使对于少量迭代也要快得多,但对于上面的数组大小,loop实际上更快:

>>> %timeit noloop()
10 loops, best of 3: 64.7 ms per loop
>>> %timeit loop()
10 loops, best of 3: 41.6 ms per loop
Run Code Online (Sandbox Code Playgroud)

有趣的是,如果我*2在两个函数中删除,noloop更快,但只是轻微:

>>> %timeit noloop()
10 loops, best of 3: 29.4 ms per loop
>>> %timeit loop()
10 loops, best of 3: 34.4 ms per loop
Run Code Online (Sandbox Code Playgroud)

这些结果是否有一个很好的解释,是否有一个明显更快的方式来执行相同的任务?

Dun*_*nes 0

我无法重现你的结果,但我确实发现使用numpy.multiply. 通过使用该out参数,您可以利用内存已分配的事实并消除tmpto的复制out

def out_loop():
    out = np.empty((arr1.size, arr2.size))
    for i in range(arr1.size):
        np.multiply(arr1[i], arr2, out=out[i].reshape((1, arr2.size)))
        out[i] *= 2
    return out
Run Code Online (Sandbox Code Playgroud)

我的机器上的结果:

In [32]: %timeit out_loop()
100 loops, best of 3: 17.7 ms per loop

In [33]: %timeit loop()
10 loops, best of 3: 28.3 ms per loop
Run Code Online (Sandbox Code Playgroud)