具有 3D 向量的两个 numpy 数组的点积

Dot product of two numpy arrays with 3D Vectors

我的目标是找到距离单个点最近的线段(在线段数组中)。 获取 2D 坐标数组之间的点积有效,但使用 3D 坐标会出现以下错误:

*ValueError: matmul: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (n?,k),(k,m?)->(n?,m?) (size 2 is different from 3)*


A = np.array([[1,1,1],[2,2,2]])
B = np.array([[3,3,3], [4,4,4]])

dp = np.dot(A,B)

dp 应该 return 2 个值, [1,1,1]@[3,3,3][2,2,2]@[4,4,4]

的点积

// 谢谢大家

这里是找到离单个点最近的线段的最终解决方案。
欢迎任何优化。

import numpy as np
import time

#find closest segment to single point

then = time.time()

#random line segment
l1 = np.random.rand(1000000, 3)*10   
l2 = np.random.rand(1000000, 3)*10

#single point
p = np.array([5,5,5]) #only single point

#set to origin
line = l2-l1
pv = p-l1  

#length of line squared
len_sq = np.sum(line**2, axis = 1) #len_sq = numpy.einsum("ij,ij->i", line, line)

#dot product of 3D vectors with einsum
dot = np.einsum('ij,ij->i',line,pv) #np.sum(line*pv,axis=1)


#percentage of line the pv vector travels in
param = np.array([dot/len_sq])

#param<0 projected point=l1, param>1 pp=l2
clamped_param = np.clip(param,0,1)

#add line fraction to l1 to get projected point
pp = l1+(clamped_param.T*line)

##distance vector between single point and projected point
pp_p = pp-p

#sort by smallest distance between projected point and l1
index_of_mininum_dist = np.sum(pp_p**2, axis = 1).argmin()

print(index_of_mininum_dist)
print("FINISHED IN: ", time.time()-then)

numpy 的点积显然不是为与数组一起使用而设计的。围绕它编写一些包装器非常容易。例如:

def array_dot(A, B):
    return [A[i]@B[i] for i in range(A.shape[0])]

np.dot 仅适用于向量,不适用于矩阵。传递矩阵时,它希望进行矩阵乘法,但由于传递的维数会失败。

在矢量上它会像你预期的那样工作:

np.dot(A[0,:],B[0,:])
np.dot(A[1,:],B[1,:])

一次性完成:

np.sum(A*B,axis=1)

你是这个意思吗:

np.einsum('ij,ij->i',A,B)

输出:

[ 9 24]

但是,如果您想要 A 中的每一行与 B 中的每一行的点积,您应该这样做:

A@B.T

输出:

[[ 9 12]
 [18 24]]
In [265]: A = np.array([[1,1,1],[2,2,2]]) 
     ...: B = np.array([[3,3,3], [4,4,4]]) 

按元素乘法后跟求和效果很好:

In [266]: np.sum(A*B, axis=1)                                                                        
Out[266]: array([ 9, 24])

einsum 也让表达变得简单:

In [267]: np.einsum('ij,ij->i',A,B)                                                                  
Out[267]: array([ 9, 24])

dot 与 2d 数组(此处为 (2,3) 形),执行矩阵乘法,经典的跨行、向下列。在 einsum 表示法中,这是 'ij,jk->ik'.

In [268]: np.dot(A,B)                                                                                
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-268-189f80e2c351> in <module>
----> 1 np.dot(A,B)

<__array_function__ internals> in dot(*args, **kwargs)

ValueError: shapes (2,3) and (2,3) not aligned: 3 (dim 1) != 2 (dim 0)

使用转置,维度匹配 (2,3) 与 (3,2),但结果是 (2,2):

In [269]: np.dot(A,B.T)                                                                              
Out[269]: 
array([[ 9, 12],
       [18, 24]])

所需的值在对角线上。

问题的一种思路是我们要做一批1d的产品。添加 matmul/@ 以执行批量矩阵乘法(dot 无法执行)。但是数组必须扩展到 3d,所以 batch 维度是领先的维度(并且 3 在各自的最后一个和第二个到最后一个维度):

In [270]: A[:,None,:]@B[:,:,None]       # (2,1,3) with (2,3,1)                                                              
Out[270]: 
array([[[ 9]],

       [[24]]])

但是结果是(2,1,1)形的。正确的数字在那里,但我们必须挤出额外的维度。

总的来说,前 2 个解决方案是最简单的 - 总和或乘积或 einsum 等价物。