numpy 在一维布尔数组中查找相邻区域

ru9i0ody  于 12个月前  发布在  其他
关注(0)|答案(7)|浏览(147)

如果我有一个布尔值的1D数组,比如np.array([True, False, True, True True, False, True, True]),我希望有一个函数可以返回True的所有相邻区域的索引。
例如,在上面的数组上调用这个函数的输出将产生类似[(0,0), (2,4), (6,7)]的结果。
我不知道如何很好地完成这一点,我也希望能够用PyTorchTensor来做到这一点。

piv4azn7

piv4azn71#

我已经在我写的一个名为haggis的实用程序库中实现了这个功能。函数是haggis.npy_util.mask2runs。我写它的部分原因是为了解决堆栈溢出上反复出现的这个问题:

runs = haggis.math.mask2runs(mask)

字符串
第二列是排他索引,因为这在python和numpy中更有用,所以您可能需要

runs[:, -1] -= 1


这个函数没有什么特别的。你可以用numpy把它写成一行程序:

runs = numpy.flatnonzero(np.diff(numpy.r_[numpy.int8(0), mask.view(numpy.int8), numpy.int8(0)])).reshape(-1, 2)

o2gm4chl

o2gm4chl2#

这是一个只有一行代码的numpy实现。
适用于输入。我还没有测试过边缘情况,但应该也可以工作
如果你需要代码的到来,干杯:)

import numpy as np

a = np.array([True, False, True, True, True, False, True, True])

#Indices are found here
a_true_ranges = np.argwhere(np.diff(a,prepend=False,append=False))

#Conversion into list of 2-tuples
a_true_ranges = a_true_ranges.reshape(len(a_true_ranges)//2,2)
a_true_ranges = [tuple(r) for r in a_true_ranges]
a_true_ranges
#[(0, 1), (2, 5), (6, 8)]

字符串

8hhllhi2

8hhllhi23#

我找到了一个解决方案:

def find_contigs(mask):
    """
    Find contiguous regions in a mask that are True with no False in between
    """
    assert len(mask.shape) == 1 # 1D tensor of bools 
    
    contigs = []
    found_contig = False 
    for i,b in enumerate(mask):
        
        
        if b and not found_contig:   # found the beginning of a contig
            contig = [i]
            found_contig = True 
        
        elif b and found_contig:     # currently have contig, continuing it 
            pass 
        
        elif not b and found_contig: # found the end, record previous index as end, reset indicator  
            contig.append(i-1)
            found_contig = False 
            contigs.append(tuple(contig))
        
        else:                        # currently don't have a contig, and didn't find one 
            pass 
    
    
    # fence post bug - check if the very last entry was True and we didn't get to finish 
    if b:
        contig.append(i)
        found_contig = False 
        contigs.append(tuple(contig))
        
    return contigs

字符串

l5tcr1uw

l5tcr1uw4#

我不确定是否有一个很好的纯Numpy方法来实现这一点,但既然看起来你愿意循环,你可以使用itertools.groupby并跟踪索引和组长度:

from itertools import groupby

a = np.array([True, False, True, True, True, False, True, True])

i = 0
res = []

for k, g in groupby(a):
    l = len(list(g))
    if k:
        res.append((i,i+l))
    i += l

print(res)
# [(0, 1), (2, 5), (6, 8)]

字符串
如果你想要闭区间,显然你可以从第二个元组值中减去1。
你也可以把它写成一个生成器,这样在内存中使用长列表时会更友好一些:

from itertools import groupby

a = np.array([True, False, True, True, True, False, True, True])

def true_indices(a):
    i = 0
    for k, g in groupby(a):
        l = len(list(g))
        if k:
            yield (i,i+l)
        i += l

list(true_indices(a))
# [(0, 1), (2, 5), (6, 8)]

dtcbnfnu

dtcbnfnu5#

我对Pytorch不是很熟悉,但这个问题本身看起来很容易解决。你需要遍历整个列表,并存储找到的应急区域的第一个索引。我使用了-1,因为它超出了任何索引的范围。从那里,你只需将一个元组添加到一个包含已保存索引和当前索引的列表中,并将起始索引重置为-1.由于这依赖于找到一个False布尔值,我在循环外添加了一个非重置开始索引的最终检查,这意味着从那里到列表末尾有一个应急区域。
我说的是当前指数,但为了保持它的入站,我减去1,使它更符合你想要的。

def getConRegions(booleanList):
    conRegions=[]
    start=-1
    for index,item in enumerate(booleanList):
        if item and start<0:start=index
        elif start>=0 and not item:
            conRegions.append((start,index-1))
            start=-1
    if(start>=0):conRegions.append((start,len(booleanList)-1))
    return conRegions
print(getConRegions([True,False,True,True,True,False,True,True]))

字符串

cclgggtu

cclgggtu6#

我卑微的解决方案:

list = [True, False, True, True, True, False, True, True]
if list[-1] == True:
    list.extend([False])

answers = []
beginning = "yes"

for index, value in enumerate(list):
    if value == True and beginning == "yes":
        x = index
        beginning = "not anymore"
    elif value == True:
        pass
    else:
        answers.append((x, index -1))
        beginning = "yes"
        
print(answers)

字符串

输出:

[(0, 0), (2, 4), (6, 7)]

dzjeubhm

dzjeubhm7#

基于numpy的快速解决方案:

import numpy as np

def find_contigs(arr):
    indices = []
    # Each number in this array will be the index of an
    # element in 'arr' just *before* it switches
    nonzeros = np.nonzero(np.diff(arr))[0]

    # Case if array begins with True
    if arr[0]:
        if len(nonzeros):
            indices.append((0, nonzeros[0] + 1))
        else:
            indices.append((0, len(arr)))
        nonzeros = nonzeros[1:]

    # Correct for array ending in True
    if len(nonzeros) % 2:
        final_idx = (nonzeros[-1] + 1, len(arr))
        nonzeros = nonzeros[:-1]
    else:
        final_idx = None

    # Parse nonzero indices
    nonzeros += 1
    nonzeros = nonzeros.reshape((len(nonzeros)//2, 2))
    indices.extend([(a, b) for a, b in zip(nonzeros[:, 0], nonzeros[:, 1])])
    if final_idx is not None:
        indices.append(final_idx)

    return indices

字符串

相关问题