繁体   English   中英

在Python中有效地找到scipy / numpy中非零的间隔?

[英]efficiently finding the interval with non-zeros in scipy/numpy in Python?

假设我有一个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]。

谢谢。

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

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

这适用于我的多个洞

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

实际上,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)

对于nonzero_coords([0, 0, 0, 0, 1, 2, 3, 4])返回(4, 8)不是(4, 7) nonzero_coords([0, 0, 0, 0, 1, 2, 3, 4]) ,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 == []

如果你还是装了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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM