【问题标题】:Convert 1d array to lower triangular matrix将一维数组转换为下三角矩阵
【发布时间】:2018-12-28 13:44:50
【问题描述】:

我想在保留所有数字的同时将一维数组转换为较低的零对角矩阵。

我知道numpy.tril 函数,但它用零替换了一些元素。我需要扩展矩阵以包含所有原始数字。

例如:

[10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]

应该是

0
10 0
20 40 0
46 33 14 0
12 46 52 30 0
59 18 11 22 30 0
2 11 58 22 72 12 0

【问题讨论】:

    标签: python python-3.x numpy


    【解决方案1】:

    输入数组包含填充较低对角线位置所需的所有值,这是masking 的一种方法-

    def fill_lower_diag(a):
        n = int(np.sqrt(len(a)*2))+1
        mask = np.tri(n,dtype=bool, k=-1) # or np.arange(n)[:,None] > np.arange(n)
        out = np.zeros((n,n),dtype=int)
        out[mask] = a
        return out
    

    示例运行 -

    In [82]: a
    Out[82]: 
    array([10, 20, 40, 46, 33, 14, 12, 46, 52, 30, 59, 18, 11, 22, 30,  2, 11,
           58, 22, 72, 12])
    
    In [83]: fill_lower_diag(a)
    Out[83]: 
    array([[ 0,  0,  0,  0,  0,  0,  0],
           [10,  0,  0,  0,  0,  0,  0],
           [20, 40,  0,  0,  0,  0,  0],
           [46, 33, 14,  0,  0,  0,  0],
           [12, 46, 52, 30,  0,  0,  0],
           [59, 18, 11, 22, 30,  0,  0],
           [ 2, 11, 58, 22, 72, 12,  0]])
    

    5k x 5k 形状的大型数组的计时 -

    In [146]: np.random.seed(0)
    
    In [147]: n = 5000
    
    In [148]: a = np.random.randint(0,9,n*(n+1)/2)
    
    In [149]: %timeit tril_indices_app(a) #@Brenlla's solution
    1 loop, best of 3: 218 ms per loop
    
    In [151]: %timeit fill_lower_diag(a) # From this post
    10 loops, best of 3: 43.1 ms per loop
    

    【讨论】:

    • 是的,掩码索引可以更快,内存效率更高(假设您正在索引enough elements)。我的方法只对较小的k 相对于三角矩阵大小具有竞争力
    • @Brenlla 我认为这也是关于生成这些索引而不是获取显示差异的掩码,特别是对于大型数组而言。
    • 是的,这是真的。在你的计时代码中不应该是n*(n-1)吗?
    • @Brenlla 啊,是的,谢谢。它将生成 5001 x 5001 形状的阵列。时间应该不会有太大变化。
    【解决方案2】:

    你也可以使用 numpy 函数np.tril_indices:

    arr = np.array([10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12])
    n = int(np.sqrt(len(arr)*2))+1
    

    生成零矩阵并用您的值填充下部:

    idx = np.tril_indices(n, k=-1, m=n)
    matrix = np.zeros((n,n)).astype(int)
    matrix[idx] = arr
    array([[ 0,  0,  0,  0,  0,  0,  0],
           [10,  0,  0,  0,  0,  0,  0],
           [20, 40,  0,  0,  0,  0,  0],
           [46, 33, 14,  0,  0,  0,  0],
           [12, 46, 52, 30,  0,  0,  0],
           [59, 18, 11, 22, 30,  0,  0],
           [ 2, 11, 58, 22, 72, 12,  0]])
    

    【讨论】:

      【解决方案3】:

      你也可以试试下面的函数来获取列表。

      import pprint
      
      def get_triangled_list(l, rows, typ='lower'):
          if type(l) is not list:
              print 'First parameter should be a list'
              return None
      
          if type(rows) is not int:
              print 'Second parameter should be a list'
              return None
      
          if not(typ == 'lower' or typ == 'upper'):
              print 'ERROR:', typ, 'is not allowed type'
              return None
      
          new_l = []
          length = len(l)
          num_items = ((rows-1) * rows)/ 2
      
          if length != num_items:
              print 'ERROR: ', 'There should be exactly', num_items, 'items for ', rows, 'rows, found', length, 'items.'
              return None
      
          if typ == 'upper':
              for i in range(rows):
                  temp_l = [0]*(i+1) + [l.pop(0) for j in range(7-(i+1))] 
                  new_l.append(temp_l)
          elif typ=='lower':
              for i in range(rows):
                  temp_l = [l.pop(0) for j in range(i)] + [0]*(rows-i)
                  new_l.append(temp_l)
      
          return new_l
      
      if __name__ == '__main__':
          l = [10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]
      
          # TEST CASE 1 (LOWER TRIANGLE, default)
          new_lower = get_triangled_list(l, 7)
          pprint.pprint(new_lower)
          print('\n')
      
          # TEST CASE 2 (UPPER TRIANGLE, passing one more parameter)
          l = [10,20,40,46,33,14,12,46,52,30,59,18,11,22,30,2,11,58,22,72,12]
          new_upper = get_triangled_list(l, 7, 'upper')
          pprint.pprint(new_upper)
      

      输出 »

      [[0, 0, 0, 0, 0, 0, 0],
       [10, 0, 0, 0, 0, 0, 0],
       [20, 40, 0, 0, 0, 0, 0],
       [46, 33, 14, 0, 0, 0, 0],
       [12, 46, 52, 30, 0, 0, 0],
       [59, 18, 11, 22, 30, 0, 0],
       [2, 11, 58, 22, 72, 12, 0]]
      
      
      [[0, 10, 20, 40, 46, 33, 14],
       [0, 0, 12, 46, 52, 30, 59],
       [0, 0, 0, 18, 11, 22, 30],
       [0, 0, 0, 0, 2, 11, 58],
       [0, 0, 0, 0, 0, 22, 72],
       [0, 0, 0, 0, 0, 0, 12],
       [0, 0, 0, 0, 0, 0, 0]]
      

      【讨论】:

        猜你喜欢
        • 2022-10-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-06-17
        • 2011-04-18
        • 2018-11-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多