【问题标题】:numpy first non zero value of vectors in a multi dimentional arraynumpy 多维数组中向量的第一个非零值
【发布时间】:2020-02-07 02:45:35
【问题描述】:

我有一个形状为 (i,j,k) 的 3 维 numpy ndarray,其中每一行都是多个类似大小的向量的数组。

我想提取一个 (i,k) 形状的数组,使得行的每个元素都包含其“j”向量组的第一个非零元素

所以基本上,给定一个数组,例如:

[
  [
    [0 , 10 , 12 ,  0 , 4],
    [0 ,  0 , 13 ,  1 , 2],
    [12, 14 ,  1 , 12 , 8]
  ],

  [
    [5 , 17 , 12 ,  9 , 0],
    [0 ,  0 , 13 ,  1 , 0],
    [12, 14 ,  1 , 12 , 8]
  ],

  [
    [0 , 0  , 19 ,  0 , 9],
    [2 , 6  , 13 ,  0 , 2],
    [12, 14 ,  1 , 12 , 8]
  ]
]

我正在寻找类似的东西:


[
  [12, 10, 12, 1, 4],
  [5 , 17, 12, 9, 8],
  [2 , 6, 19, 12, 9]
]


如何高效地查找结果?

import numpy as np

i,j,k = 3, 5, 10 #in real problem, these are pretty large
arr = np.random.randint(0, 10000, (i,j,k))
#????????

【问题讨论】:

    标签: python arrays numpy


    【解决方案1】:

    使用简单的转置https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html 和高级索引https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#advanced-indexing,解决方案如下所示:

    import numpy as np
    
    a = np.array([
      [
        [0 , 10 , 12 ,  0 , 4],
        [0 ,  0 , 13 ,  1 , 2],
        [12, 14 ,  1 , 12 , 8]
      ],
    
      [
        [5 , 17 , 12 ,  9 , 0],
        [0 ,  0 , 13 ,  1 , 0],
        [12, 14 ,  1 , 12 , 8]
      ],
    
      [
        [0 , 0  , 19 ,  0 , 9],
        [2 , 6  , 13 ,  0 , 2],
        [12, 14 ,  1 , 12 , 8]
      ]
    ])
    
    # swapping the 0 and 1 axes, to make the rest of the code easier
    a = a.transpose((1, 0, 2))
    
    # initialising result to zeroes, same shape as a single layer of the transposed a
    result = np.zeros(a[0].shape, np.int32)
    
    # one layer at a time
    for layer in a:
        # as soon as result contains no more zeroes, done
        if len(result[result == 0]) == 0:
            break
        else:
            # replace all values of result that are zero
            # with values from the same location in layer
            result[result == 0] = layer[result == 0]
    
    print(result)
    

    打印:

    [[12 10 12  1  4]
     [ 5 17 12  9  8]
     [ 2  6 19 12  9]]
    

    【讨论】:

      【解决方案2】:

      这不是最优雅的方式,因为我很快就写好了。不过,希望这足以让您入门。

      def find_non_zero(lst):
        for num in lst:
          if num != 0:
            return num
      

      首先,我们定义一个非常简单的辅助函数find_non_zero,它接收一个一维列表作为输入并返回第一个非零条目。然后,当我们遍历提供的三维输入数组arrays 中的二维数组的每一列时,就会使用此函数。

      import numpy as np
      
      arrays = [
        [
          [0 , 10 , 12 ,  0 , 4],
          [0 ,  0 , 13 ,  1 , 2],
          [12, 14 ,  1 , 12 , 8]
        ],
      
        [
          [5 , 17 , 12 ,  9 , 0],
          [0 ,  0 , 13 ,  1 , 0],
          [12, 14 ,  1 , 12 , 8]
        ],
      
        [
          [0 , 0  , 19 ,  0 , 9],
          [2 , 6  , 13 ,  0 , 2],
          [12, 14 ,  1 , 12 , 8]
        ]
      ]
      
      final_result = []
      for array in arrays:
        array = np.array(array).T  
        final_result.append([find_non_zero(col) for col in array])
      
      print(final_result)
      

      这会产生以下输出。

      [[12, 10, 12, 1, 4], [5, 17, 12, 9, 8], [2, 6, 19, 12, 9]]
      

      Numpy 的.T 转置运算符派上用场,因为它允许我们按列而不是默认行循环遍历二维数组。有关转置运算符的更多信息,请阅读official documentation

      我很乐意回答您可能有的任何其他问题。

      【讨论】:

      • 根据口味,OP 可能更喜欢基于 Python 的解决方案,而不是仅使用 numpy 的解决方案。正如您所料,它有点慢 - 我使用timeit 对您的解决方案和我的numpy 进行了基准测试,我的100,000 次迭代大约需要1.41 秒,而您的大约需要1.62 秒。数量少,但数量少。
      【解决方案3】:

      使用沿轴应用,然后应用非零函数并获取所需轴中的第一个元素

      np.apply_along_axis(lambda e: e[np.nonzero(e)][0], 1, x)
      

      np.apply_along_axis(lambda e: e[(e!=0).argmax()], 1, x)
      

      输出

      array([[12, 10, 12,  1,  4],
             [ 5, 17, 12,  9,  8],
             [ 2,  6, 19, 12,  9]])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多