【问题标题】:Transform matrix columns into diagonal matrices and wrap them up without for loops将矩阵列转换为对角矩阵并在没有 for 循环的情况下将它们包装起来
【发布时间】:2020-12-05 12:49:52
【问题描述】:

我有 M 向量,每个向量都有 N 条目(MxN 矩阵,如果你愿意的话):

A = [A1, A2, ... , AN]
B = [B1, B2, ... , BN]
...
Z = [Z1, Z2, ... , ZN]

我想将这些转换为:

[[[A1,  0, ... ,  0],
  [0,  B1, ... ,  0],
   ...
  [0,   0, ... , Z1]],
  
 [[A2,  0, ... ,  0],
  [0,  B2, ... ,  0],
   ...
  [0,   0, ... , Z2]],
  
  ...
  
 [[AN,  0, ... ,  0],
  [0,  BN, ... ,  0],
   ...
  [0,   0, ... , ZN]]]

我们的目标是完全不使用 for 循环,而仅通过 numpy 操作来实现这一点。想法?

【问题讨论】:

  • 嗨 Chanto,你试过了吗?
  • 嗨,伊万。是的,我试过np.diag,但它只适用于一维或二维数组,而不是我想要的方式。现在我正在尝试用矩阵乘法来实现它。
  • 我们希望看到minimal reproducible example
  • 这是一个很模糊的问题。有多种方法可以做到这一点。你试过 np.fill_diagonal numpy.org/doc/stable/reference/generated/…

标签: python arrays numpy matrix diagonal


【解决方案1】:

我遇到了一个示例 here,它使用 np.apply_along_axis 填充多个对角线。


A = [11, 12, 13, 14]
B = [21, 22, 23, 24]
C = [31, 32, 33, 34]
D = [41, 42, 43, 44]
E = [51, 52, 53, 54]

Z = np.array([A, B, C, D, E])

构造 Z 后,将其转置并用其值填充一个空的对角线数组:

>>> np.apply_along_axis(np.diag, -1, Z.T)
array([[[11,  0,  0,  0,  0],
        [ 0, 21,  0,  0,  0],
        [ 0,  0, 31,  0,  0],
        [ 0,  0,  0, 41,  0],
        [ 0,  0,  0,  0, 51]],

       [[12,  0,  0,  0,  0],
        [ 0, 22,  0,  0,  0],
        [ 0,  0, 32,  0,  0],
        [ 0,  0,  0, 42,  0],
        [ 0,  0,  0,  0, 52]],

       [[13,  0,  0,  0,  0],
        [ 0, 23,  0,  0,  0],
        [ 0,  0, 33,  0,  0],
        [ 0,  0,  0, 43,  0],
        [ 0,  0,  0,  0, 53]],

       [[14,  0,  0,  0,  0],
        [ 0, 24,  0,  0,  0],
        [ 0,  0, 34,  0,  0],
        [ 0,  0,  0, 44,  0],
        [ 0,  0,  0,  0, 54]]])

【讨论】:

    【解决方案2】:

    虽然您的问题很清楚,但我们更愿意看到 [MCVE](该标签在评论中展开,请参阅 SO 介绍)。当要求无循环解决方案时,展示一个有效的循环解决方案是礼貌的——这给了我们一些测试依据。我至少想证明我的答案有效。

    所以这是我的最小工作示例 - 使用循环解决方案:

    In [308]: M = np.stack([np.arange(i,j) for i,j in zip([1,11,21],[5,15,25])])
    In [309]: M.shape
    Out[309]: (3, 4)
    In [310]: M
    Out[310]: 
    array([[ 1,  2,  3,  4],
           [11, 12, 13, 14],
           [21, 22, 23, 24]])
    In [311]: np.stack([np.diag(M[:,i]) for i in range(4)])
    Out[311]: 
    array([[[ 1,  0,  0],
            [ 0, 11,  0],
            [ 0,  0, 21]],
    
           [[ 2,  0,  0],
            [ 0, 12,  0],
            [ 0,  0, 22]],
    
           [[ 3,  0,  0],
            [ 0, 13,  0],
            [ 0,  0, 23]],
    
           [[ 4,  0,  0],
            [ 0, 14,  0],
            [ 0,  0, 24]]])
    

    np.diagonal 让我们指定轴。因此,例如我们可以使用它从Out[311] 中提取起始数组:

    In [318]: np.diagonal(Out[311],axis1=1, axis2=2)
    Out[318]: 
    array([[ 1, 11, 21],
           [ 2, 12, 22],
           [ 3, 13, 23],
           [ 4, 14, 24]])
    

    我没有(直接)看到多维建筑。我们可以在文档中挖掘更多,或者查看现有代码来构造一个等价物。或者只是接受该循环的时间损失:)

    diag(onal) 函数使用flat 索引来提高速度,但使用多维索引更容易。我们可以使用

    访问这些相同的值
    In [319]: Out[311][:,np.arange(3),np.arange(3)]
    Out[319]: 
    array([[ 1, 11, 21],
           [ 2, 12, 22],
           [ 3, 13, 23],
           [ 4, 14, 24]])
    

    我们可以使用相同的索引来赋值。

    In [320]: res = np.zeros((4,3,3),int)
    In [321]: res[:,np.arange(3), np.arange(3)] = M.T
    In [322]: res
    Out[322]: 
    array([[[ 1,  0,  0],
            [ 0, 11,  0],
            [ 0,  0, 21]],
    
           [[ 2,  0,  0],
            [ 0, 12,  0],
            [ 0,  0, 22]],
    
           [[ 3,  0,  0],
            [ 0, 13,  0],
            [ 0,  0, 23]],
    
           [[ 4,  0,  0],
            [ 0, 14,  0],
            [ 0,  0, 24]]])
    

    如果最后这些步骤令人困惑,我建议您尝试创建自己的二维对角数组。从小处着手,并以这些知识为基础。

    【讨论】:

      【解决方案3】:

      您可以使用 diag numpy 函数,例如

      import numpy as np
      
      A = [0, 1, 2]
      B = [0, 1, 2]
      C = [0, 1, 2]
      
      # Merge lists into matrix
      X = np.array([A, B, C])
      
      # Index columns and merge into list of diagonal matrices
      print([np.diag(X[:, 0]), np.diag(X[:, 1]), np.diag(X[:, 2])])
      

      要自动化最后一步(如上),您可能需要使用 for 循环,例如

      diag_list = []
      for n in N:
         diag_list.append(np.diag(X[:, n])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-21
        • 2020-05-12
        • 1970-01-01
        • 2014-05-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多