np.dot 是矩阵乘法的推广。
在常规矩阵乘法中,一个 (N,M) 形矩阵与一个 (M,P) 形矩阵相乘得到一个 (N,P) 形矩阵。最终的形状可以被认为是通过将两个形状挤压在一起((N,M,M,P))然后删除中间数字M(以产生(N,P))来形成的。这是np.dot 在推广到更高维数组时保留的属性。
当文档说,
"对于 N 维,它是 a 的最后一个轴上的和积和
b" 的倒数第二个。
说到这一点。形状为(u,v,M) 的数组与形状为(w,x,y,M,z) 的数组之间的点缀将产生一个形状为(u,v,w,x,y,z) 的数组。
让我们看看这条规则在应用于时的样子
In [25]: V = np.arange(2); V
Out[25]: array([0, 1])
In [26]: M = np.arange(4).reshape(2,2); M
Out[26]:
array([[0, 1],
[2, 3]])
首先,简单的部分:
In [27]: np.dot(M, V)
Out[27]: array([1, 3])
这里没有惊喜;这只是矩阵向量乘法。
现在考虑
In [28]: np.dot(V, M)
Out[28]: array([2, 3])
看V和M的形状:
In [29]: V.shape
Out[29]: (2,)
In [30]: M.shape
Out[30]: (2, 2)
所以np.dot(V,M) 就像一个 (2,) 形矩阵与一个 (2,2) 形矩阵的矩阵乘法,应该得到一个 (2,) 形矩阵。
V 的最后一个(也是唯一的)轴和M 的倒数第二个轴(也就是M 的第一个轴)相乘和相加,只剩下@987654337 的最后一个轴@。
如果你想可视化这个:np.dot(V, M) 看起来好像 V 有 1 行和 2 列:
[[0, 1]] * [[0, 1],
[2, 3]]
因此,当 V 乘以 M 时,np.dot(V, M) 等于
[[0*0 + 1*2], [2,
[0*1 + 1*3]] = 3]
但是,我真的不建议尝试以这种方式可视化 NumPy 数组——至少我从不这样做。我几乎完全专注于形状。
(2,) * (2,2)
\ /
\ /
(2,)
您只需考虑“中间”轴被点缀,并从结果形状中消失。
np.sum(arr, axis=0) 告诉 NumPy 对 arr 中的元素求和 消除 第 0 轴。如果arr 是二维的,则第 0 轴是行。例如,如果arr 看起来像这样:
In [1]: arr = np.arange(6).reshape(2,3); arr
Out[1]:
array([[0, 1, 2],
[3, 4, 5]])
然后np.sum(arr, axis=0) 将沿列求和,从而消除第 0 轴(即行)。
In [2]: np.sum(arr, axis=0)
Out[2]: array([3, 5, 7])
3是0+3的结果,5等于1+4,7等于2+5。
注意arr 的形状为 (2,3),求和后第 0 轴被移除,因此结果为形状 (3,)。第 0 个轴的长度为 2,每个总和由这 2 个元素相加组成。形状 (2,3) “变成” (3,)。您可以提前知道最终的形状!这可以帮助指导您的思考。
要测试您的理解,请考虑np.sum(arr, axis=1)。现在删除了 1 轴。所以结果形状将是(2,),结果中的元素将是 3 个值的总和。
In [3]: np.sum(arr, axis=1)
Out[3]: array([ 3, 12])
3 等于 0+1+2,12 等于 3+4+5。
所以我们看到对轴求和消除结果中的那个轴。这与np.dot 有关,因为np.dot 执行的计算是产品的sum。由于np.dot 沿某些轴执行求和运算,因此从结果中删除了该轴。这就是为什么将np.dot 应用于形状为 (2,) 和 (2,2) 的数组会产生一个形状为 (2,) 的数组。将两个数组中的第一个 2 相加,消除两者,只留下第二个数组中的第二个 2。