Python 带外积的向量化和约化-NumPy

Python 带外积的向量化和约化-NumPy,python,numpy,vectorization,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:- 方法#2:带+- 方法#3:带有np.einsum+- 运行时测试 第1组: 第2组: 第

我对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:-

方法#2:带+-

方法#3:带有
np.einsum
+-


运行时测试 第1组:

第2组:

第三种方法把其他一切都搞砸了

为什么
方法#3
方法#1
快10-130倍?

np.einsum
是用C实现的。在第一种方法中,有三个字符串
i
j
k
,在其字符串表示法中,我们将有三个嵌套循环(当然是用C实现的)。这是很大的内存开销


在第三种方法中,我们只使用了两个字符串
i
j
,因此使用了两个嵌套循环(再次使用C),还利用了基于BLAS的
矩阵乘法
,即
np.dot
。这两个因素导致了这一次惊人的加速。

哇,谢谢!np.einsum的加速非常好<代码>%timeit np.sum(w[i]*np.outer(p[i],p[i])对于范围内的i(len(p)))76.8µs±313 ns/循环(平均±标准偏差为7次,每个循环10000次)
%timeit np.einsum('ij,ik,i->->jk',p,p,p,w)5.49µs±43.5 ns/循环(平均±标准偏差为7次,每个循环100000次)
%timeit np tensord(p[…,None],p[:]=((0),(0)))23.9µs±510 ns/循环(7次运行的平均值±标准偏差,每个循环10000次)@joe-92为更大的阵列添加了计时。@Divakar,你对einsum和dot的组合比纯einsum快有什么解释吗?似乎NumPy 1.14在可能的情况下会将BLAS用于
einsum
()。也许这会提高第一次进近的速度。@joe-92好消息!我们只需要看看“可能的时候”部分的进展如何。但确实有希望。
np.einsum('ij,ik,i->jk',p,p,w)
np.tensordot(p[...,None]*p[:,None], w, axes=((0),(0)))
np.einsum('ij,i->ji',p,w).dot(p)
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
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