Python 为什么2d阵列和1d阵列的numpy点积会产生1d阵列?

Python 为什么2d阵列和1d阵列的numpy点积会产生1d阵列?,python,numpy,Python,Numpy,我尝试运行以下代码: >>> 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)

我尝试运行以下代码:

>>> 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])

为什么会出现这种结果?

在wiki中

所以带(2,1)的(3,2)点将是(3,1)


如何修复

np.dot(A,B[:,None])
Out[49]: 
array([[23],
       [53],
       [83]])

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

鉴于这一主要目的,
numpy.dot()
的作者也将此场景作为第一个场景(下面的第一个要点):

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

只有当
B
的形状为
(2,1)
时,您才有理由期望结果形状为
(3,1)
。在这种情况下,由于
a
具有形状
(3,2)
,而
B
具有形状
(2,1)
,因此您有理由期望结果形状为
(3,1)

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

我引用了这个答案,并对代码进行了一些修改:

根据numpy,1D数组只有一个维度和所有检查 都是针对那个维度做的。正因为如此,我们发现np.dot(A,B) 检查A的第二个维度与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)
A.shape是(3,2),B.shape是(2),这种情况可以直接使用规则#4进行点操作np.dot(A,B):

如果a是N-D数组,b是1-D数组,则它是a和b最后一个轴的和积


因为对齐将发生在B的2(只有B的轴)和A的2(A的最后一个轴)之间,并且2确实等于2,numpy将判断这对于点操作是绝对合法的。因此这两个“2”被“消耗”,留下A的(3),“在野外”。这(3,)因此将是结果的形状。

我刚从神经网络学习了这个点积。。。 无论如何,它是“1d”数组和“nd”数组之间的点积。

如我们所见,它将红色框中元素的乘法和分别计算为“17+28” 然后


那么
1
维度从何而来?它不在
A
(3,2)或
B
(3,1)中。你可以想象
B
被扩展到(3,1),但结果是(3,1)。这就是
matmul
解释动作的方式。但它挤出了添加的维度。可能重复将
A
视为线性映射。是否应该使用线性映射(或运算符)应用于一维数组会产生二维数组?为什么不使用一维数组?在
numpy
1d数组实际上是一维的,不是伪装的行或列向量。@Champer Wu。我不想在对话中使用col vector和row vector这两个词,因为它们似乎有点模棱两可。如果你只说“形状”,你可能会发现自己更容易理解(m,)数组”或“形状(m,1)数组”或“形状(1,m)数组”,这取决于您试图传达的内容。我知道许多专家确实使用这些术语,但我还是不愿意使用,至少在本次对话中是这样。
numpy
没有
vector
类。因此B不是矩阵。它是列和行的向量?理想情况下,您应该键入数组,而不是链接到pic特尔斯
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.
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)