【问题标题】:efficiently finding the interval with non-zeros in scipy/numpy in Python?在 Python 的 scipy/numpy 中有效地找到非零的区间?
【发布时间】:2011-02-06 20:16:54
【问题描述】:

假设我有一个 python 列表或一个 python 一维数组(以 numpy 表示)。假设有一段连续的元素我怎样才能找到这个列表或数组中非零段的开始和结束坐标(即索引)?例如,

a = [0, 0, 0, 0, 1, 2, 3, 4]

nonzero_coords(a) 应该返回 [4, 7]。为:

b = [1, 2, 3, 4, 0, 0]

nonzero_coords(b) 应该返回 [0, 2]。

谢谢。

【问题讨论】:

    标签: python arrays numpy scipy


    【解决方案1】:

    假设有一个连续的非零元素......

    x = nonzero(a)[0]
    result = [x[0], x[-1]]
    

    【讨论】:

    • 是的,我认为这样就解决了。相比之下,我的答案看起来有点傻......
    • 这会因多个孔而失败。作者不够具体。此外,虽然这似乎是最简单的解决方案,但我不确定它是否是最快的解决方案。
    • @Hamish - 当然这将比纯 Python 解决方案快得多,因为这里的数组循环在 C 中而不是在 Python 中运行。此外,当 OP 没有提到如何处理链中的零时,将其称为失败并不是真正正确的,所以最好的办法是陈述给定方法的假设,我显然这样做了。 (顺便说一句,你的答案只是选择了第一个连续链,先验当然没有更好,但它没有提到这个限制。)
    • @Hamish - 当然......这里没问题。我只是想直接解决你的观点。无论如何,根据我的经验,我提出的解决方案是解决这个问题的好方法;但你的批评混淆了这一点,所以我只是想解释为什么“非零”仍然是一个很好的解决方案。对于没有使用特定方法经验的人,像您这样的批评可能会不恰当地降低他们尝试这种方法的兴趣。
    【解决方案2】:

    这对我来说适用于多个洞

    from numpy import *
    def nonzero_intervals(value):
        lvalue = array(value)
        lvalue[0] = 0
        lvalue[-1] = 0
        a = diff((lvalue==0) * 1)
        intervals = zip( find(a == -1),find(a == 1))
        return intervals
    

    【讨论】:

      【解决方案3】:

      实际上,nonzero_coords(b) 应该返回 [0, 3]。输入端会出现多个孔吗?如果是,那该怎么办?天真的解决方案:扫描直到第一个非零 el。然后扫描到最后一个非零的el。代码如下(抱歉没有测试):

      a = [0, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0]
      start = 0
      size = len(a) # 
      while (start < size and a[start] != 0): start += 1
      end = start
      while (end < size and a[end] != 0): end += 1
      return (start, end)
      

      【讨论】:

        【解决方案4】:

        对于nonzero_coords([0, 0, 0, 0, 1, 2, 3, 4]) 返回(4, 8)(4, 7) 更符合python 索引,因为[0, 0, 0, 0, 1, 2, 3, 4][4:8] 返回[1, 2, 3, 4]

        这是一个计算非零区间的函数。它处理多个间隔:

        def nonzero_intervals(vec):
            '''
            Find islands of non-zeros in the vector vec
            '''
            if len(vec)==0:
                return []
            elif not isinstance(vec, np.ndarray):
                vec = np.array(vec)
        
            edges, = np.nonzero(np.diff((vec==0)*1))
            edge_vec = [edges+1]
            if vec[0] != 0:
                edge_vec.insert(0, [0])
            if vec[-1] != 0:
                edge_vec.append([len(vec)])
            edges = np.concatenate(edge_vec)
            return zip(edges[::2], edges[1::2])
        

        如果您真的希望答案包含在岛中的结束索引,您可以将最后一行更改为:return zip(edges[::2], edges[1::2]-1)

        测试:

        a = [0, 0, 0, 0, 1, 2, 3, 4]
        intervals = nonzero_intervals(a)
        assert intervals == [(4, 8)]
        
        a = [1, 2, 3, 4, 0, 0]
        intervals = nonzero_intervals(a)
        assert intervals == [(0, 4)]
        
        a=[1, 2, 0, 0, 0, 3, 4, 0]
        intervals = nonzero_intervals(a)
        assert intervals == [(0, 2), (5, 7)]
        
        a = [0, 4, 0, 6, 0, 6, 7, 0, 9]
        intervals = nonzero_intervals(a)
        assert intervals == [(1, 2), (3, 4), (5, 7), (8, 9)]
        
        a = [1, 2, 3, 4]
        intervals = nonzero_intervals(a)
        assert intervals == [(0, 4)]
        
        a = [0, 0, 0]
        intervals = nonzero_intervals(a)
        assert intervals == []
        
        a = []
        intervals = nonzero_intervals(a)
        assert intervals == []
        

        【讨论】:

          【解决方案5】:

          如果你已经加载了 numpy,请使用 tom10 的答案。

          如果出于某种原因你想要一些不加载 numpy 的东西(无法想象为什么,老实说),那么我建议这样:

          from itertools import groupby
          
          def nonzero_coords(iterable):
            start = 0
            for iszero, sublist in groupby(iterable, lambda x:x==0):
              if iszero:
                start += len(list(sublist))
              else:
                return start, start+len(list(sublist))-1
          

          【讨论】:

            猜你喜欢
            • 2011-08-18
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-09-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多