在布尔数组中保留True的前导和尾随岛 - NumPy

时间:2017-07-15 03:40:16

标签: python numpy

鉴于我有这个1d-numpy阵列。

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

结果显示:

b = np.array([True True True False False False False False False False False False False False False False False True True])

为清晰起见,已编辑: 我如何(1)在1d数组的前导和尾随位置保持True值的“岛”,同时(2)将所有其他True值转换为False,用于不在前导或尾随“岛”中的真值1d阵列?

我已经尝试过明显的非效率答案,即通过它进行天真的迭代,但我不禁觉得有更好的解决方案。任何人都有更好的主意吗?

感谢您的阅读! :)

4 个答案:

答案 0 :(得分:2)

方法#1

这是一种利用slicingnumpy.maximum.accumulate来检测岛屿起点和终点指数的方法 -

def fill_inner_islands(a):
    acc = np.maximum.accumulate
    start = a.argmax()
    end = a.size-a[::-1].argmax()
    a0 = ~a[start:end]
    a[start:end] = ~(acc(a0) & acc(a0[::-1])[::-1])

样品运行 -

案例#1:

In [140]: a.astype(int)
Out[140]: array([1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1])

In [141]: fill_inner_islands(a)

In [142]: a.astype(int)
Out[142]: array([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1])

案例#2:

In [144]: a.astype(int)
Out[144]: array([1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])

In [145]: fill_inner_islands(a)

In [146]: a.astype(int)
Out[146]: array([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0])

案例#3:

In [148]: a.astype(int)
Out[148]: array([1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0])

In [149]: fill_inner_islands(a)

In [150]: a.astype(int)
Out[150]: array([1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0])

方法#2

更简单的方法 -

def fill_inner_islands_v2(a):
    # Get stop and end indices of leading and trailing islands.
    # We do this by using one-off shifted slices and looking for the fall
    # in forward direction and fall in flipped direction   
    start = (a[1:] < a[:-1]).argmax()+1
    end = a.size - 1 - (a[:-1][::-1] < a[1:][::-1]).argmax()

    # Get the slice within those indices and assign as all False
    if ~a[start:end].all(): # To handle all True in input array
        a[start:end] = 0

答案 1 :(得分:1)

>>> a
array([ True,  True,  True, False, False, False, False,  True,  True,
       False,  True, False, False, False, False, False, False,  True,  True], dtype=bool)

假设数组以True开始和结束;使用np.diff找到True-False,False-True中断

>>> b = np.diff(a)
>>> b
array([False, False,  True, False, False, False,  True, False,  True,
        True,  True, False, False, False, False, False,  True, False], dtype=bool)

使用np.where

查找这些中断的索引
>>> c = np.where(b)
>>> c = c[0]
>>> c
array([ 2,  6,  8,  9, 10, 16], dtype=int64)
>>>
>>> # c = b.nonzero()[0]

再次,假设数组以True开始和结束 - 您只关心第一个和最后一个中断

>>> x, y = c[0], c[-1]
>>> x, y
(2, 16)
>>>

在作业的左侧使用这些索引

 >>> a[x+1:y] = False
>>> a
array([ True,  True,  True, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False,  True,  True], dtype=bool)
>>> 

答案 2 :(得分:0)

我为您提供了以下解决方案,它打算快速将False设置为所有数据,然后恢复值。由于numpy数组的实例化,我不知道这是否比迭代每个值更快,但这是一种不同的方法,它不会改变a的内容并且不会循环。

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

b = np.array([False] * len(a))
b[0] = a[0]; b[-1] = a[-1]

根据您的反馈更新:

这很难看,但是没有循环,所以你可能会发现大量的True / False值很有趣。请注意,此处的数组不是一个numpy数组。

a = [True, True, True, False, False, True]
start = a.index(False)
a.reverse()
end = a.index(False) * -1
a.reverse()

result = a[:start] + [False] * (len(a) - (start + end * -1)) + a[end:]

答案 3 :(得分:0)

此问题的任何解决方案都涉及迭代。这是一个没有任何显式循环的东西:

b = a.tolist()
start = b.index(False)
end = b[::-1].index(False)
if end:
    a[start : -end] = False
else:
    a[start : ] = False