为什么两个数组的点积产生标量而转置数组的点积产生矩阵?
在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 个回答
你看过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
的术语中,我喜欢把它看作是“乘积之和”的维度。
矩阵乘法基本上是点积的矩阵版本。记住,点积的结果是一个标量,而矩阵乘法的结果是一个矩阵,其元素是每个矩阵中向量对的点积。