Skip to main content
 首页 » 编程设计

python之为什么二维数组与一维数组的 numpy 点积会产生一维数组

2025年05月04日13xing901022

我尝试运行如下代码:

>>> import numpy as np 
>>> A = np.array([[1,2], [3,4], [5,6]]) 
>>> A.shape 
(3, 2) 
>>> B = np.array([7,8]) 
>>> B.shape 
(2,) 
>>> np.dot(A,B) 
array([23, 53, 83]) 

我认为 np.dot(A,B) 的形状应该是 (1,3) 而不是 (3,)。

矩阵返回的结果应该是:

数组([[23],[53],[83]])

23 
53 
83 

不是

数组([23,53,83])

23 53 83 

为什么会出现这个结果?

请您参考如下方法:

顾名思义,numpy.dot() 函数的主要目的是通过对两个数组执行传统线性代数点积 来提供标量结果相同形状的 (m,)。

鉴于此主要目的,documentation numpy.dot() 的第一个也谈到了这种情况(下面的第一个要点):

numpy.dot(a, b, out=None) 
 
 1. If both a and b are 1-D arrays, it is inner product of vectors (without complex conjugation). 
 2. If both a and b are 2-D arrays, it is matrix multiplication, but using matmul or a @ b is preferred. 
 3. If either a or b is 0-D (scalar), it is equivalent to multiply and using numpy.multiply(a, b) or a * b is preferred. 
 4. If a is an N-D array and b is a 1-D array, it is a sum product over the last axis of a and b. 

您的案例包含在他的评论中的上述第 4 个要点(正如@hpaulj 所指出的)。 但是,它仍然没有完全回答您的问题,即为什么结果的形状为 (3,),而不是您预期的 (3,1)。

只有当 B 的形状为 (2,1) 时,您才有理由期待 (3,1) 的结果形状>。在这种情况下,由于 A 的形状为 (3,2),而 B 的形状为 (2,1),您有理由期待 (3,1) 的结果形状。

但是在这里,B 的形状是(2,),而不是(2,1)。因此,我们现在处于通常矩阵乘法规则管辖范围之外的领域。因此,结果如何完全取决于 numpy.dot() 函数的设计者。他们本可以选择将此视为错误(“维度不匹配”)。相反,他们选择处理这种情况,如 this answer 中所述。 .

我引用了那个答案,并做了一些修改以关联您的代码:

According to numpy a 1D array has only 1 dimension and all checks are done against that dimension. Because of this we find that np.dot(A,B) checks second dimension of A against the one dimension of B

因此,检查会成功,numpy 不会将其视为错误。

现在,唯一剩下的问题是为什么结果形状是 (3,) 而不是 (3,1) 或 (1,3) 。

答案是:在形状为(3,2) 的A 中,我们消费 最后一部分(2,) 执行和积。 A 形状的 未使用 部分是 (3,),因此 np.dot(A,B) 结果的形状>,将是 (3,)。为了进一步理解这一点,如果我们举一个不同的例子,其中 A 的形状是 (3,4,2),而不是 (3,2) ,A 形状的未消耗部分将是 (3,4,),而 np.dot(A ,B) 将是 (3,4,) 而不是您的示例生成的 (3,)。

下面是验证码:

import numpy as np 
 
A = np.arange(24).reshape(3,4,2) 
print ("A is:\n", A, ", and its shape is:", A.shape) 
B = np.array([7,8]) 
print ("B is:\n", B, ", and its shape is:", B.shape) 
C = np.dot(A,B) 
print ("C is:\n", C, ", and its shape is:", C.shape) 

这个的输出是:

A is: 
 [[[ 0  1] 
  [ 2  3] 
  [ 4  5] 
  [ 6  7]] 
 
 [[ 8  9] 
  [10 11] 
  [12 13] 
  [14 15]] 
 
 [[16 17] 
  [18 19] 
  [20 21] 
  [22 23]]] , and its shape is: (3, 4, 2) 
B is: 
 [7 8] , and its shape is: (2,) 
C is: 
 [[  8  38  68  98] 
 [128 158 188 218] 
 [248 278 308 338]] , and its shape is: (3, 4) 

另一个有助于理解此示例中的行为的视角如下:

形状为(3,4,2)的数组A可以在概念上可视化为内部数组的外部数组,其中外部数组的形状为 (3,4),每个内部数组的形状都是(2,)。因此,在这些内部数组中的每一个上,将使用数组 B(其形状为 (2,))执行传统的点积,结果标量全部保留在各自的位置,组成一个(3,4)形状(外矩阵形状)。所以,numpy.dot(A,B)的整体结果,由所有这些就地标量结果组成,形状为 (3,4)。