Python 使用Numpy的成对vdot

Python 使用Numpy的成对vdot,python,numpy,vectorization,Python,Numpy,Vectorization,我试图计算一个复杂的2D数组的成对np.vdot。因此,我想要的行为是: X = np.empty((x.shape[0], x.shape[0]), dtype='complex128') for i in range(x.shape[0]): for j in range(x.shape[0]): X[i, j] = np.vdot(x[i], x[j]) 有没有一种不用显式循环就能做到这一点的方法?我尝试使用sklearn中的pairwise\u内核,但它假设输入

我试图计算一个复杂的2D数组的成对
np.vdot
。因此,我想要的行为是:

X = np.empty((x.shape[0], x.shape[0]), dtype='complex128')
for i in range(x.shape[0]):
    for j in range(x.shape[0]):
        X[i, j] = np.vdot(x[i], x[j])
有没有一种不用显式循环就能做到这一点的方法?我尝试使用
sklearn
中的
pairwise\u内核
,但它假设输入数组是实数。我也尝试过广播,但
vdot
会将其输入平坦化

X = np.einsum('ik,jk->ij', np.conj(x), x)
相当于

X = np.empty((x.shape[0], x.shape[0]), dtype='complex128')
for i in range(x.shape[0]):
    for j in range(x.shape[0]):
        X[i, j] = np.vdot(x[i], x[j])
取乘积之和。下标
'ik,jk->ij'
告诉
np.einsum
第二个参数,
np.conj(x)
是一个带有下标
ik
的数组,第三个参数
x
具有 下标
jk
。因此,对所有的变量计算乘积
np.conj(x)[i,k]*x[j,k]
i
j
k
。该总和将接管重复的下标k,此后 剩下的
i
j
将成为结果数组的下标


比如说,

import numpy as np

N, M = 10, 20
a = np.random.random((N,M))
b = np.random.random((N,M))
x = a + b*1j

def orig(x):
    X = np.empty((x.shape[0], x.shape[0]), dtype='complex128')
    for i in range(x.shape[0]):
        for j in range(x.shape[0]):
            X[i, j] = np.vdot(x[i], x[j])
    return X

def alt(x):
    return np.einsum('ik,jk->ij', np.conj(x), x)

assert np.allclose(orig(x), alt(x))


要将
np.vdot
扩展到所有行,您可以使用,我直接借用共轭思想,如下所示-

np.tensordot(np.conj(x),x,axes=(1,1))
基本上,使用
np.tensordot
,我们指定了要缩减的轴,在本例中,这是共轭版本的
x
和数组本身的最后一个轴,当应用于这两个轴时

运行时测试-

让我们在这篇文章中讨论时间和建议的解决方案-

In [27]: import numpy as np # From @unutbu's` solution again
    ...: 
    ...: N, M = 1000, 1000
    ...: a = np.random.random((N,M))
    ...: b = np.random.random((N,M))
    ...: x = a + b*1j
    ...: 

In [28]: %timeit np.einsum('ik,jk->ij', np.conj(x), x) # @unutbu's` solution
1 loops, best of 3: 4.45 s per loop

In [29]: %timeit np.tensordot(np.conj(x),x,axes=(1,1))
1 loops, best of 3: 3.76 s per loop
In [27]: import numpy as np # From @unutbu's` solution again
    ...: 
    ...: N, M = 1000, 1000
    ...: a = np.random.random((N,M))
    ...: b = np.random.random((N,M))
    ...: x = a + b*1j
    ...: 

In [28]: %timeit np.einsum('ik,jk->ij', np.conj(x), x) # @unutbu's` solution
1 loops, best of 3: 4.45 s per loop

In [29]: %timeit np.tensordot(np.conj(x),x,axes=(1,1))
1 loops, best of 3: 3.76 s per loop