【问题标题】:Multiplying specific dimension matrices乘以特定维度矩阵
【发布时间】:2014-05-05 06:35:18
【问题描述】:

假设我有矩阵 A 和 B。

A 是一个三维数组/张量(?)。

[1,2,3,4]
[5,6,7,8]
[1,2,3,4]
[5,6,7,8]

说有 4 个不同的 2d 矩阵,就像上面的那样跨越第三维。

B 是一个矩阵。

[1,2,3,4]

B中也有4个,每个都是一样的。

如何将 B 中的每个向量(?)与 A 中的每个二维矩阵相乘。

[1,2,3,4]*[1,2,3,4]*[1;2;3;4]
          [5,6,7,8]
          [1,2,3,4]
          [5,6,7,8]

将有四个上述类型的乘法得到四个 4x1 向量。 我已经用 numpy 试过了:

y = numpy.arange(4).reshape(1,4)
z = numpy.arange(64).reshape(4,4,4)
y.dot(z).dot(numpy.transpose(y))
------
Output:
array([[[ 420],
        [ 996],
        [1572],
        [2148]]])

它可以按我的意愿工作。但我不知道 numpy 是如何广播的,我想知道出于学习目的,以及其他用于处理不同库中矩阵的包以不同方式处理广播。我试图以不同的方式平铺 B 以获得相同的结果,但没有任何效果。如果我没有解释清楚,请告诉我。

还希望从 numpy 获得 4x1 而不是 3d 返回。

【问题讨论】:

    标签: python numpy matrix


    【解决方案1】:

    您可能想查看np.einsum。举个例子:

    >>> mat = np.arange(80).reshape(4, 4, 5)
    >>> vec = np.arange(12).reshape(3, 4)
    >>> np.einsum('ij,jkl,ik->il', vec, mat, vec)
    array([[ 2100,  2136,  2172,  2208,  2244],
           [20900, 21384, 21868, 22352, 22836],
           [58900, 60344, 61788, 63232, 64676]])
    

    如果我没有弄错索引,我有 5 个形状为 4x4 的矩阵和 3 个长度为 4 的向量,并且正在用每个向量计算每个矩阵的 3x5 二次形式。

    【讨论】:

    • 这不会复制 OP 的双 dot,因为 dot 使用第二个参数的第二个到最后一个维度。
    • 但是他的第二个参数是一维的。我认为它确实符合他的要求,这似乎是一个二次形式。无论如何,他应该能够通过摆弄索引来得到他想要的。
    【解决方案2】:

    请注意,np.dot 在不同维度数组中的行为与here 不同:

    对于二维数组,它等价于矩阵乘法,

    对于一维数组到向量的内积(没有复杂的 共轭)。

    对于 N 维,它是最后一个的和积 a的轴和b的倒数第二个

    在您的示例中,z 有 3 个维度。

    另外,还有一个important distinction between a numpy array and a numpy matrix

    您在示例中使用了数组。 Numpy 矩阵仅是 2D 的,矩阵乘法是通过 * 运算符实现的。 (对于数组,这将执行逐个元素的乘法)

    【讨论】:

      【解决方案3】:

      为了使尺寸保持直线,我将使用变量。通常在测试中我喜欢在每个维度上使用不同的尺寸(例如z=...reshape(3,4,5)),所以错误会跳出来。

      k,j,l = 4
      y = numpy.arange(4).reshape(1,j)
      z = numpy.arange(64).reshape(k,j,l)
      

      y.dot(z) 将结合y 的最后一个暗淡与z (j) 的倒数第二个(参见其文档)。结果将是(1,k,l)

      np.einsum 有助于确认这一点:

      print y.dot(z)
      print np.einsum('ij,kjl',y,z) # note the repeated j
      

      两者都产生

      array([[[ 56,  62,  68,  74],
              [152, 158, 164, 170],
              [248, 254, 260, 266],
              [344, 350, 356, 362]]])
      

      y.T (转置) 是 (j,1)。所以第二个点将(1,k,l)(j,1) 组合在一起,最后一个暗淡(l)与第一个j 组合在一起,得到(1,k,1),你的3d 数组:

      array([[[ 420],
              [ 996],
              [1572],
              [2148]]])
      
      np.einsum('ijl,lm', np.einsum('ij,kjl',y,z), y.T) # note the repeated l
      

      这个einsum 可以合并为一个调用(使用相同的索引):

      np.einsum('ij,kjl,ml',y,z,y)
      

      不涉及广播。也就是说,没有添加或扩展任何维度。您只需要在维度通过dot 时系统地跟踪它们。

      要获得更小维度的结果,您需要挤出 1 或重塑结果。如果您从一维 y 开始,您会得到一维结果

      y1=y.squeeze()
      np.einsum('j,kjl,l',y1,z,y1)
      y1.dot(z).dot(y1.T)
      # array([ 420,  996, 1572, 2148])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-09-08
        • 1970-01-01
        • 2021-11-24
        • 2013-08-15
        • 1970-01-01
        • 1970-01-01
        • 2020-08-16
        相关资源
        最近更新 更多