
2.4.9 各种乘积运算
与本节内容对应的Notebook为:02-numpy/numpy-460-functions-dot.ipynb。
本节介绍的函数如表2-9所示。
表2-9 本节要介绍的函数

矩阵的乘积可以使用dot( )计算。对于二维数组,它计算的是矩阵乘积;对于一维数组,它计算的是内积。当需要将一维数组当作列矢量或行矢量进行矩阵运算时,先将一维数组转换为二维数组:
a = np.array([1, 2, 3]) a[:, None] a[None, :] ---------- ----------- [[1], [[1, 2, 3]] [2], [3]]
对于多维数组,dot( )的通用计算公式如下,即结果数组中的每个元素都是:数组a的最后轴上的所有元素与数组b的倒数第二轴上的所有元素的乘积和:
dot(a, b)[i,j,k,m] = sum(a[i,j,:] *
b[k,:,m])
下面以两个三维数组的乘积演示dot( )的计算结果。首先创建两个三维数组,这两个数组的最后两轴满足矩阵乘积的条件:
a = np.arange(12).reshape(2, 3, 2) b = np.arange(12, 24).reshape(2, 2, 3) c = np.dot(a, b) c.shape (2, 3, 2, 3)
c是数组a和b的多个子矩阵的乘积。我们可以把数组a看作两个形状为(3,2)的矩阵,而把数组b看作两个形状为(2,3)的矩阵。a中的两个矩阵分别与b中的两个矩阵进行矩阵乘积,就得到数组c,c[i, :, j, :]是a中第i个矩阵与b中第j个矩阵的乘积。
for i, j in np.ndindex(2, 2): assert np.alltrue( c[i, :, j, :] == np.dot(a[i], b[j]) )
对于两个一维数组,inner( )和dot( )一样,计算两个数组对应下标元素的乘积和。而对于多维数组,它计算的结果数组中的每个元素都是:数组a和b的最后轴的内积。因此数组a和b的最后轴的长度必须相同:
inner(a, b)[i,j,k,m] = sum(a[i,j,:]*
b[k,m,:])
下面是对inner( )的演示:
a = np.arange(12).reshape(2, 3, 2) b = np.arange(12, 24).reshape(2, 3, 2) c = np.inner(a, b) c.shape (2, 3, 2, 3)
for i, j, k, l in np.ndindex(2, 3, 2, 3): assert c[i, j, k, l] == np.inner(a[i, j], b[k, l])
outer( )只对一维数组进行计算,如果传入的是多维数组,则先将此数组展平为一维数组之后再进行运算。它计算列向量和行向量的矩阵乘积:
a = np.array([1, 2, 3]) b = np.array([4, 5, 6, 7]) np.outer(a, b) np.dot(a[:, None], b[None, :]) ------------------ ------------------------------ [[ 4, 5, 6, 7], [[ 4, 5, 6, 7], [ 8, 10, 12, 14],[ 8, 10, 12, 14], [12, 15, 18, 21]][12, 15, 18, 21]]
tensordot( )将两个多维数组a和b指定轴上的对应元素相乘并求和,它是最一般化的乘积运算函数。下面通过一些例子逐步介绍其用法。下面计算两个矩阵的乘积:❶axes参数有两个元素,第一个元素表示a中的轴,第二个元素表示b中的轴,这两个轴上对应的元素相乘之后求和。❷axes也可以是一个整数,它表示把a中的后axes个轴和b中的前axes个轴进行乘积和运算,而对于乘积和之外的轴则保持不变。
a = np.random.rand(3, 4) b = np.random.rand(4, 5) c1 = np.tensordot(a, b, axes=[[1], [0]]) ❶ c2 = np.tensordot(a, b, axes=1) ❷ c3 = np.dot(a, b) assert np.allclose(c1, c3) assert np.allclose(c2, c3)
对于多维数组的dot( )乘积,可以用tensordot(a, b, axes=[[-1], [-2]])表示,即将a的最后轴和b中的倒数第二轴求乘积和:
a = np.arange(12).reshape(2, 3, 2) b = np.arange(12, 24).reshape(2, 2, 3) c1 = np.tensordot(a, b, axes=[[-1], [-2]]) c2 = np.dot(a, b) assert np.alltrue(c1 == c2)
在下面的例子中,将a的第1、第2轴与b的第1、第0轴求乘积和,因此c中的每个元素都是按照如下表达式计算的:
c[i, j, k, l] = np.sum(a[i, :, :, j] *
b[:, :, k, l].T)
注意由于b对应的axes中的轴是倒序的,因此需要做转置操作。
a = np.random.rand(4, 5, 6, 7)
b = np.random.rand(6, 5, 2, 3)
c = np.tensordot(a, b, axes=[[1, 2], [1, 0]])
for i, j, k, l in np.ndindex(4, 7, 2, 3):
assert np.allclose(c[i, j, k, l], np.sum(a[i, :, :, j] *
b[:, :, k, l].T))
c.shape
(4, 7, 2, 3)