简体   繁体   English

两个 numpy arrays 与 3D 向量的点积

[英]Dot product of two numpy arrays with 3D Vectors

My goal is finding the closest Segment (in an array of segments) to a single point.我的目标是找到离单点最近的段(在段数组中)。 Getting the dot product between arrays of 2D coordinates work, but using 3D coordinates gives the following error:获取二维坐标的 arrays 之间的点积可以工作,但使用 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 should return 2 values, The dot product of [1,1,1]@[3,3,3] and [2,2,2]@[4,4,4] dp应该返回 2 个值, [1,1,1]@[3,3,3][2,2,2]@[4,4,4]的点积

// Thanks everyone. // 感谢大家。

Here is the final solution to find the closest line segment to a single point.这是找到离单点最近的线段的最终解决方案。
Any optimization is welcome.欢迎任何优化。

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)

np.dot works only on vectors, not matrices. np.dot 仅适用于向量,不适用于矩阵。 When passing matrices it expects to do a matrix multiplication, which will fail because of the dimensions passed.传递矩阵时,它期望进行矩阵乘法,由于传递的维度,这将失败。

On a vector it will work like you expected:在向量上它会像你预期的那样工作:

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

To do it in one go:在一个 go 中做到这一点:

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

Do you mean this:你是这个意思吗:

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

output: output:

[ 9 24]

However, if you want the dot product of every row in A with every row in B, you should do:但是,如果您想要 A 中的每一行与 B 中的每一行的点积,您应该这样做:

A@B.T

output: output:

[[ 9 12]
 [18 24]]

The dot product is numpy is not designed to be used with arrays apparently.点积是 numpy 显然不是为与 arrays 一起使用而设计的。 It's pretty easy to write some wrapper around it.围绕它编写一些包装器非常容易。 Like this for example:像这样的例子:

def array_dot(A, B):
    return [A[i]@B[i] for i in range(A.shape[0])]
In [265]: A = np.array([[1,1,1],[2,2,2]]) 
     ...: B = np.array([[3,3,3], [4,4,4]]) 

Element wise multiplication followed by sum works fine:元素明智的乘法,然后是 sum 工作正常:

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

einsum also makes expressing this easy: einsum也使表达这一点变得容易:

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

dot with 2d arrays (here (2,3) shaped), performs matrix multiplication, the classic across rows, down columns. dot与 2d arrays(此处为 (2,3) 形状),执行矩阵乘法,经典的跨行、向下列。 In einsum notation this is 'ij,jk->ik'.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)

With a transpose, dimensions match (2,3) with (3,2),but the result is (2,2):使用转置,尺寸匹配 (2,3) 和 (3,2),但结果是 (2,2):

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

The desired values are on the diagonal.所需值位于对角线上。

One way to think of the problem is that we want to do a batch of 1d products.思考这个问题的一种方法是我们想做一批一维产品。 matmul/@ was added to perform batch matrix multiplication (which dot can't do).添加matmul/@以执行批量矩阵乘法( dot不能这样做)。 But the arrays have to be expanded to 3d, so the batch dimension is the leading one (and the 3 is on the respective last and 2nd to the last dimensions):但是 arrays 必须扩展为 3d,因此批次维度是前导维度(并且 3 分别位于最后一个维度和第二个到最后一个维度):

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

       [[24]]])

But the result is (2,1,1) shaped.但结果是 (2,1,1) 形的。 The right numbers are there, but we have to squeeze out the extra dimensions.正确的数字在那里,但我们必须挤出额外的维度。

Overall then the first 2 solutions are simplest - sum or product or einsum equivalent.总的来说,前 2 个解决方案是最简单的 - sum 或 product 或einsum等价物。

Function numpy.dot works with numpy.ndarray objects. Function numpy.dot 适用于 numpy.ndarray 对象。 The example below works.下面的例子有效。

import numpy as np

A = np.zeros((3, 3))
B = np.zeros((3, 3))
print(type(A))
# <class 'numpy.ndarray'>
C = np.dot(A, B)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM