33

我正在学习 NumPy,但我不确定操作员*实际上在做什么。这似乎是某种形式的乘法,但我不确定它是如何确定的。来自 ipython:

In [1]: import numpy as np

In [2]: a=np.array([[1,2,3]])

In [3]: b=np.array([[4],[5],[6]])

In [4]: a*b
Out[4]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [5]: b*a
Out[5]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [6]: b.dot(a)
Out[6]: 
array([[ 4,  8, 12],
       [ 5, 10, 15],
       [ 6, 12, 18]])

In [7]: a.dot(b)
Out[7]: array([[32]])

似乎它正在做矩阵乘法,但只b乘以a,而不是相反。到底是怎么回事?

4

2 回答 2

28

这有点复杂,与广播的概念以及所有 numpy 操作都是元素明智的事实有关。

  1. a是一个 1 行 3 列b的二维数组,是一个 1 列 3 行的二维数组。
  2. 如果您尝试将它们逐个元素相乘(如果您这样做,那么 numpy 会尝试这样做,a * b因为除了操作之外的每个基本操作dot都是元素明智的),它必须广播数组,以便它们在所有维度上都匹配。
  3. 由于第一个数组是 1x3,第二个是 3x1,因此可以根据广播规则将它们广播到 3x3 矩阵。它们看起来像:
a = [[1, 2, 3],
     [1, 2, 3],
     [1, 2, 3]]

b = [[4, 4, 4],
     [5, 5, 5],
     [6, 6, 6]]

现在 Numpy 可以将它们逐个元素相乘,得到结果:

[[ 4,  8, 12],
 [ 5, 10, 15],
 [ 6, 12, 18]]

当您进行.dot操作时,它会执行标准矩阵乘法。更多文档

于 2013-08-17T22:27:57.397 回答
10

*进行元素乘法。

由于数组具有不同的形状,因此将应用广播规则。

In [5]: a.shape
Out[5]: (1, 3)

In [6]: b.shape
Out[6]: (3, 1)

In [7]: (a * b).shape
Out[7]: (3, 3)
  1. 所有 ndim 小于最大 ndim 输入数组的输入数组,在其形状前添加 1(此处不适用)。
  2. 输出形状的每个维度中的大小是该维度中所有输入大小的最大值。
  3. 如果输入在特定维度中的大小与该维度中的输出大小匹配,或者其值恰好为 1,则可以在计算中使用该输入。
  4. 如果输入在其形状中的维度大小为 1,则该维度中的第一个数据条目将用于沿该维度的所有计算。换句话说,ufunc 的步进机器根本不会沿着该维度步进(该维度的步幅将为 0)。

因此,生成的形状必须是(3, 3)(最大值ab维度大小),并且在执行乘法时,numpy 不会逐步通过 a 的第一维度和 b 的第二维度(它们的大小为 1)。

结果的[i][j]元素等于广播的元素a和元素的乘积。b[i][j]

(a * b)[0][0] == a[0][0] * b[0][0]
(a * b)[0][1] == a[0][1] * b[0][0]  # (not stepping through b's second dimension)
(a * b)[0][2] == a[0][2] * b[0][0]
(a * b)[1][0] == a[0][0] * b[1][0]  # (not stepping through a's first dimension)

etc.
于 2013-08-17T22:28:00.163 回答