外部产品的矢量化减少 - NumPy

时间:2017-12-23 17:13:09

标签: python numpy vectorization

我对NumPy比较新,经常读到你应该避免写循环。在很多情况下,我理解如何处理,但目前我有以下代码:

p = np.arange(15).reshape(5,3)
w = np.random.rand(5)
A = np.sum(w[i] * np.outer(p[i], p[i]) for i in range(len(p)))

有没有人知道是否有办法避免内部for循环?

提前致谢!

1 个答案:

答案 0 :(得分:6)

方法#1:使用np.einsum -

np.einsum('ij,ik,i->jk',p,p,w)

方法#2: broadcasting + np.tensordot -

np.tensordot(p[...,None]*p[:,None], w, axes=((0),(0)))

方法#3: np.einsum + np.dot -

np.einsum('ij,i->ji',p,w).dot(p)

运行时测试

设置#1:

In [653]: p = np.random.rand(50,30)

In [654]: w = np.random.rand(50)

In [655]: %timeit np.einsum('ij,ik,i->jk',p,p,w)
10000 loops, best of 3: 101 µs per loop

In [656]: %timeit np.tensordot(p[...,None]*p[:,None], w, axes=((0),(0)))
10000 loops, best of 3: 124 µs per loop

In [657]: %timeit np.einsum('ij,i->ji',p,w).dot(p)
100000 loops, best of 3: 9.07 µs per loop

设置#2:

In [658]: p = np.random.rand(500,300)

In [659]: w = np.random.rand(500)

In [660]: %timeit np.einsum('ij,ik,i->jk',p,p,w)
10 loops, best of 3: 139 ms per loop

In [661]: %timeit np.einsum('ij,i->ji',p,w).dot(p)
1000 loops, best of 3: 1.01 ms per loop

第三种方法只是吹响了其他一切!

为什么Approach #3Approach #1快10x-130x?

np.einsum在C中实现。在第一种方法中,使用字符串表示法中的那三个字符串ijk,我们将有三个字符串嵌套循环(当然在C中)。那里有很多内存开销。

使用第三种方法,我们只进入两个字符串ij,因此有两个嵌套循环(再次在C中),并且还利用基于BLAS的matrix-multiplicationnp.dot 1}}。这两个因素是这个因素的惊人加速。

相关问题