我正在阅读Numpy Tutorial,并且说这样的示例代码如下:
>>> X = np.ones(10, dtype=np.int)
>>> Y = np.ones(10, dtype=np.int)
>>> A = 2*X + 2*Y
很慢,因为它会创建三个不同的中间数组,以保存A
,2*X
和2*Y
的值。
相反,建议如果速度是个问题,请执行相同的计算:
>>> X = np.ones(10, dtype=np.int)
>>> Y = np.ones(10, dtype=np.int)
>>> np.multiply(X, 2, out=X)
>>> np.multiply(Y, 2, out=Y)
>>> np.add(X, Y, out=X)
但我没看到速度差异在哪里。在第二个代码中,X
和Y
似乎仍然被创建为中间数组。区别在于np.multiply
而不是2*X
的速度吗?
答案 0 :(得分:2)
这两个代码示例在他们正在做的事情上并不相同。执行2*X
时,您必须分配一个新数组。第二个例子虽然速度更快,但有点破坏性,因为你需要直接修改数组而不是为计算制作副本。
如果您打算重复使用X和Y进行多次不相互依赖的操作(也就是说,您将此操作的X和Y相乘,而不是将来的相乘),您可能需要使用初始方法,这样您就可以不必撤消操作。
答案 1 :(得分:2)
我将这两个例子包含在函数中,并尝试了一些时间:
In [136]: timeit foo1(1000)
10000 loops, best of 3: 26.4 µs per loop
In [137]: timeit foo2(1000)
10000 loops, best of 3: 27.4 µs per loop
In [138]: timeit foo1(100000)
100 loops, best of 3: 2.39 ms per loop
In [139]: timeit foo2(100000)
1000 loops, best of 3: 1.24 ms per loop
In [140]: timeit foo1(10000000)
^[[A^[1 loop, best of 3: 571 ms per loop
In [141]: timeit foo2(10000000)
10 loops, best of 3: 175 ms per loop
对于较小的尺寸,使用outs
并没有太大的区别。阵列进入10000&我们在数组重用中看到的元素大小。我怀疑使用更大的数组时,分配新数组的相对成本更高 - 更难找到可重用的块,这需要更多的OS调用等。
如果我必须先复制2个初始数组(以便重复使用),那么节省的时间就会消失。
X = np.ones(N).copy()
Y = np.ones(N).copy()
当你摆脱迭代时,这是一种需要考虑的变化。即使这样,SO答案也更有可能建议numba
或cython
。我在numpy
函数中看到了一些,但它并不突出。我想到的例外是np.cross
(np.source(np.cross)
),它使用这样的块:
# cp0 = a1 * b2 - 0 (a2 = 0)
# cp1 = 0 - a0 * b2 (a2 = 0)
# cp2 = a0 * b1 - a1 * b0
multiply(a1, b2, out=cp0)
multiply(a0, b2, out=cp1)
negative(cp1, out=cp1)
multiply(a0, b1, out=cp2)
cp2 -= a1 * b0