【问题标题】:Numpy - Matrix multiplication to return ndarray, not sumNumpy - 矩阵乘法返回ndarray,而不是总和
【发布时间】:2017-12-26 06:54:50
【问题描述】:

所有,我有一个应用程序需要在将两个矩阵相乘时返回一个 numpy ndarray,而不是一个简单的总和;例如:

import numpy as np
x = np.array([[1, 1, 0], [0, 1, 1]])
y = np.array([[1, 0, 0, 1], [1, 0, 1, 0], [0, 0, 0, 0]])
w = x @ y
>>> array([[2, 0, 1, 1],
           [1, 0, 1, 0]])

但是,要求是返回一个ndarray(在这种情况下..):

array([[[1,1,0], [0,0,0], [0,1,0], [1,0,0]],
       [[0,1,0], [0,0,0], [0,1,0], [0,0,0]]])

注意矩阵乘法运算可能会重复;输出将用作 ndarrays 的左侧矩阵,用于下一次矩阵乘法运算,这将在第二次矩阵乘法运算等之后产生更高阶的 ndarray。

有什么方法可以做到这一点?我通过子类化 np.ndarray as discussed here 查看了重载 __add____radd__,但大多出现维度不兼容错误。

想法?

更新:

解决@Divakar's answer 例如,对于链式操作,添加

z = np.array([[1, 1, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0]])
s1 = x[...,None] * y
s2 = s1[...,None] * z

导致不希望的输出。

我怀疑问题从 s1 开始,在上述情况下返回 s1.shape = (2,3,4)。应该是(2,4,3),因为[2x3][3x4] = [2x4],但是我们这里并没有真正求和,只是返回一个长度为3的数组。

同样,s2.shape 应该是 (2,3,4,3),[顺便说一下] 它是,但输出不理想(它不是“错误”,只是不是我们想要的)。 详细地说,s1*z 应该是 [2x4][4x3] = [2x3] 矩阵。矩阵的每个元素本身就是一个 [4x3] 的 ndarray,因为我们在 z 中有 4 行来乘以 s1 中的元素,并且 s1 中的每个元素本身就是 3 个元素长(同样,我们不是在算术上添加元素,而是返回 ndarrays,扩展维度是操作的 R 矩阵中的行数。

最终,所需的输出将是:

s2 = array([[[[1, 1, 0],
              [0, 0, 0],
              [0, 1, 0],
              [0, 0, 0]],

              [[1, 1, 0],
               [0, 0, 0],
               [0, 0, 0],
               [1, 0, 0]],

              [[0, 0, 0],
               [0, 0, 0],
               [0, 0, 0],
               [0, 0, 0]]],


             [[[0, 1, 0],
               [0, 0, 0],
               [0, 1, 0],
               [0, 0, 0]],

              [[0, 1, 0],
               [0, 0, 0],
               [0, 0, 0],
               [0, 0, 0]],

              [[0, 0, 0],
               [0, 0, 0],
               [0, 0, 0],
               [0, 0, 0]]]])

【问题讨论】:

  • 这看起来更像是一个外部产品。

标签: python numpy multidimensional-array matrix-multiplication


【解决方案1】:

将它们扩展到 3D 并利用 broadcasting -

x[:,None] * y.T

或者np.einsum -

np.einsum('ij,jk->ikj',x,y)

通过OP's comment 和问题的引用:

... 矩阵乘法运算可以重复;输出将 用作下一个矩阵的ndarrays的左侧矩阵 乘法运算,这将产生一个更高阶的ndarray 在第二次矩阵乘法运算等之后。

看来,我们需要按照这些思路做点什么——

s1 = x[...,None] * y
s2 = s1[...,None] * z # and so on.

虽然在这种情况下,轴的顺序会有所不同,但这似乎是将解决方案扩展到传入2D 数组的通用数量的最简单方法。

按照问题中的编辑,您似乎正在将传入的数组从第一个轴向前放置以进行元素乘法。所以,如果我做对了,你可以交换轴以获得正确的顺序,就像这样 -

s1c = (x[...,None] * y).swapaxes(1,-1)
s2c = (s1c.swapaxes(1,-1)[...,None] * z).swapaxes(1,-1) # and so on.

如果您只对最终输出感兴趣,请仅在最后阶段交换轴并跳过中间阶段的轴。

【讨论】:

  • @Divakar,谢谢,但这不能正确链接;例如:定义这个 4x3 矩阵 z = np.array([[1, 1, 0], [0, 0, 0], [1, 0, 0], [0, 1, 0]]) 并假设 s1 是您的答案的输出,以下链接操作 s1[:, None] * z.T 会引发以下错误:ValueError: operands could not be broadcast together with shapes (2,1,4,3) (3,4)
  • @GG_Python 那么你需要做z *s1。因此,获得s1 后的进一步操作将取决于传入数组的形状。
  • @GG_Python 或者 zs1 相乘的预期输出究竟是什么?你能添加预期的输出吗?
  • x[..., None, :] * y.T 怎么样?
  • @PaulPanzer s1 = x[..., None, :] * y.T 然后s2 = s1[..., None, :] * z.T?
猜你喜欢
  • 2016-05-09
  • 2017-09-19
  • 1970-01-01
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多