numpy:检测数组中的连续1

use*_*012 5 python arrays numpy

我想在numpy数组中检测1的连续跨度.实际上,我想首先确定数组中的元素是否在至少三个1的范围内.例如,我们有以下数组a:

    import numpy as np
    a = np.array([1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0])
Run Code Online (Sandbox Code Playgroud)

然后下面的1以粗体显示满足要求的元素.

[ 1,1,1,0,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,1,1,1,0]

接下来,如果两个1的跨度最多分开两个0,则两个跨距构成更长的跨度.所以上面的数组被描述为

[ 1,1,1,0,1,1,1,0,1,1,0,0,1,1,1,0,0,1,1,1,1,1,0]

换句话说,对于原始数组作为输入,我想要输出如下:

    [True, True, True, True, True, True, True, False, False, False, False, False, True, True, True, True, True, True, True, True, True, True, False]
Run Code Online (Sandbox Code Playgroud)

我一直在想一个实现这个功能的算法,但我提出的所有算法似乎都很复杂.所以我很想知道更好的方法来实现这一点 - 如果有人可以帮助我,我将不胜感激.

更新:

我道歉,我没有说清楚我的问题.我想在阵列中识别3个或更多个连续的1作为1的跨度,并且识别任何两个1的跨度,其间只有一个或两个0,以及分离0,作为单个长跨度.我的目标可以通过以下方式理解:如果在1的跨度之间只有一个或两个0,我认为那些0是错误,应该被纠正为1.

@ ritesht93提供的答案几乎可以满足我的需求.但是,当有三个1的跨度由0分隔时,当前的答案不能识别这种情况,应该将其识别为单个跨度.例如,对于数组

    a2 = np.array([0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0])
Run Code Online (Sandbox Code Playgroud)

我们应该收到输出

    [False,  True,  True,  True,  True,  True,  True,  True,  True,
   True,  True,  True,  True,  True, False, False,  False, False,
   False,  True,  True,  True,  True,  True, False]
Run Code Online (Sandbox Code Playgroud)

更新2:

我受到了极大的启发,并发现基于正则表达式的算法最容易实现和理解 - 尽管我不确定与其他方法相比的效率.最终我使用了以下方法.

    lst = np.array([0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0])
    lst1 = re.sub(r'1{3,}', lambda x:'c'*len(x.group()), ''.join(map(str, lst)))
    print lst1
Run Code Online (Sandbox Code Playgroud)

它确定了1的跨度

    0ccc0ccc00cccc00100ccccc0
Run Code Online (Sandbox Code Playgroud)

然后连接1的跨度

    lst2 = re.sub(r'c{1}0{1,2}c{1}', lambda x:'c'*len(x.group()), ''.join(map(str, lst1)))
    print lst2
Run Code Online (Sandbox Code Playgroud)

这使

    0ccccccccccccc00100ccccc0
Run Code Online (Sandbox Code Playgroud)

最终结果由.给出

    np.array(list(lst2)) == 'c'

    array([False,  True,  True,  True,  True,  True,  True,  True,  True,
    True,  True,  True,  True,  True, False, False, False, False,
   False,  True,  True,  True,  True,  True, False])
Run Code Online (Sandbox Code Playgroud)

rit*_*t93 1

我们可以将所有 0 和 1 转换为单个字符串,并将正则表达式匹配替换为另一个 char say ,而不是解决循环和维护计数的传统方法2。完成后,我们再次拆分字符串并检查bool()每个字符。

>>> import re
>>> lst=[1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0]
>>> list(map(bool, map(int, list(re.sub(r'1{3,}0{1,2}1{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))))))
[True, True, True, True, True, True, True, False, True, True, False, False, True, True, True, True, True, True, True, True, True, True, False]
>>> 
Run Code Online (Sandbox Code Playgroud)

所有操作都发生在这里:

re.sub(r'1{3,}0{1,2}1{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))
Run Code Online (Sandbox Code Playgroud)

它搜索连续出现的 3 个或更多 1,后跟最多 2 个 0,即 1 或 2 个 0,后跟 3 个或更多 1,并将整个匹配字符串替换为相同长度的 2 字符串(使用 2 因为是bool(2)True。您还可以使用tolist()in 方法NumPy从 NumPy 数组中获取列表,如下所示:np.array([1,2, 3, 4, 5, 6]).tolist()

编辑1:问题发生变化后,以下是更新后的答案:

>>> lst=[1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0]
>>> import re
>>> list(map(lambda x:False if x == 0 or x ==1 else True, map(int, list(re.sub(r'1{3,}0{1,2}1{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))))))
[True, True, True, True, True, True, True, False, False, False, False, False, True, True, True, True, True, True, True, True, True, True, False]
>>> 
Run Code Online (Sandbox Code Playgroud)

编辑2最终答案

>>> import re
>>> lst=[0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 0]
>>> while re.subn(r'[12]{3,}0{1,2}[12]{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))[1]:
...     lst=re.subn(r'[12]{3,}0{1,2}[12]{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))[0]
... 
>>> lst
'0222222222222200100111110'
>>> lst=list(re.sub(r'1{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst))))
>>> lst
['0', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '2', '0', '0', '1', '0', '0', '2', '2', '2', '2', '2', '0']
>>> list(map(lambda x:False if x == 0 or x ==1 else True, map(int, lst)))
[False, True, True, True, True, True, True, True, True, True, True, True, True, True, False, False, False, False, False, True, True, True, True, True, False]
>>> 
Run Code Online (Sandbox Code Playgroud)