为什么两个数组的点积产生标量而转置数组的点积产生矩阵?

0 投票
1 回答
57 浏览
提问于 2025-04-12 08:51

在numpy这个库里,我发现下面这两种计算的结果是不一样的。

a = np.array([1,2,3,4])
b = np.array([1,2,3,4])
dot_product1 = np.dot(a, b)    <--- I think this should be an error
print(dot_product1)

a = np.array([1,2,3,4])
b = np.array([1,2,3,4]).reshape(-1,1)
dot_product2 = np.dot(a, b)
print(dot_product2)

第一个计算的结果是一个数值30,而第二个计算的结果是一个1行1列的矩阵,也就是[30]。

我对线性代数的理解是,不能把一个1行4列的矩阵和另一个1行4列的矩阵做点乘。我以为第三行会出错,但它却成功了。

代码的第二部分计算了一个1行4列的矩阵和一个4行1列的矩阵,结果是一个1行1列的矩阵。这是我预期的结果。

有人能帮我解释一下这两种计算有什么不同吗?

1 个回答

2

你看过np.dot的文档吗?注意一下它对一维参数的说明。

In [209]: a = np.array([1,2,3,4])
     ...: b = np.array([1,2,3,4])
     ...: dot_product1 = np.dot(a, b)
     ...: print(dot_product1, type(dot_product1))
     ...: 
     ...: a = np.array([1,2,3,4])
     ...: b = np.array([1,2,3,4]).reshape(-1,1)
     ...: dot_product2 = np.dot(a, b)
     ...: print(dot_product2, type(dot_product2), dot_product2.shape)
30 <class 'numpy.int32'>
[30] <class 'numpy.ndarray'> (1,)

In [210]: a.shape, b.shape
Out[210]: ((4,), (4, 1))

第一个例子确实会产生一个标量值,也就是内积。和np.sum(a*b)是一样的。(已更正)

这是一个(4,)的数组和另一个(4,)的数组的点积。这些不是(1,4)的“行向量”。

第二个例子是把一个(4,)的数组和一个(4,1)的数组结合,结果是(1,)的形状。不是1x1的哦!

如果你想要(1,1),需要把(1,4)和(4,1)做点积。

In [211]: (a[None,:]@b).shape
Out[211]: (1, 1)

有一个关于“点积”的页面说,它可以这样计算:从代数上讲,点积被定义为两个数字序列对应项乘积的总和。 这正是你第一个例子的做法。

矩阵乘法可以看作是把dot product应用到两个矩阵的所有行和列组合上。这就是np.dot的作用,它还可以处理一个二维数组和一个一维数组的情况(你的第二个例子)。

np.dot也可以处理三维及以上的数组,尽管matmul版本通常更有用。

如果你想挑战自己,可以看看np.einsum,它使用“爱因斯坦记法”来处理这些多维乘积。

一般来说,在np.dot(A,B)中,A的最后一个维度会和B的倒数第二个维度(如果是1维的话就是唯一的维度)配对。在einsum的术语中,我喜欢把它看作是“乘积之和”的维度。

https://mkang32.github.io/python/2020/08/23/dot-product.html#:~:text=Matrix%20multiplication%20is%20basically%20a,of%20vectors%20in%20each%20matrix.

矩阵乘法基本上是点积的矩阵版本。记住,点积的结果是一个标量,而矩阵乘法的结果是一个矩阵,其元素是每个矩阵中向量对的点积。

撰写回答