我想在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])
然后以下粗体显示满足要求的元素。
[ 1,1,1 ,0, 1,1,1 ,0,1, 1,0,0, 1,1,1 ,0,0, 1,1,1,1,1 < / strong>,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]
我一直在想一个实现这个功能的算法,但我提出的所有算法似乎都很复杂。所以我很想知道更好的方法来实现这一点 - 如果有人可以帮助我,我将不胜感激。
更新
我道歉,我没有说清楚我的问题。我希望将数组中的3个或更多个连续1标识为1的跨度,并且识别中间只有一个或两个0的任何两个1的跨度,以及分离0,作为单个长跨度。我可以通过以下方式理解我的目标:如果在1的跨度之间只有一个或两个0,我认为这些0作为错误并且应该被纠正为1&# 39; S
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])
我们应该收到输出
[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]
更新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
确定了1&#39的跨度
0ccc0ccc00cccc00100ccccc0
然后连接1&#39的跨度
lst2 = re.sub(r'c{1}0{1,2}c{1}', lambda x:'c'*len(x.group()), ''.join(map(str, lst1)))
print lst2
给出了
0ccccccccccccc00100ccccc0
最终结果由
给出 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])
答案 0 :(得分:2)
我们可以使用binary dilation
和erosion
的组合来解决它,以便超过第一阶段,然后binary closing
来获得最终输出,就像这样 -
from scipy.ndimage.morphology import binary_erosion,binary_dilation,binary_closing
K = np.ones(3,dtype=int) # Kernel
b = binary_dilation(binary_erosion(a,K),K)
out = binary_closing(b,K) | b
示例运行
案例#1:
In [454]: a
Out[454]: array([1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0])
In [456]: out
Out[456]:
array([ True, True, True, True, True, True, True, False, False,
False, False, False, True, True, True, True, True, True,
True, True, True, True, False], dtype=bool)
案例#2:
In [460]: a
Out[460]:
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])
In [461]: out
Out[461]:
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], dtype=bool)
答案 1 :(得分:1)
我们可以将所有0和1转换为单个字符串,而不是解决传统的循环和维护计数方式,而是将正则表达式匹配替换为另一个字符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]
>>>
所有操作都在这里进行:
re.sub(r'1{3,}0{1,2}1{3,}', lambda x:'2'*len(x.group()), ''.join(map(str, lst)))
它搜索连续出现的3个或更多1个,然后是最多2个0,即1个或2个,然后是3个或更多1个并且替换为3个或更多个1&2;整个匹配的字符串具有相同长度的字符串2(使用2,因为bool(2)
是True
)。您也可以使用tolist()
中的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]
>>>
编辑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]
>>>
答案 2 :(得分:1)
我知道这不是“python-wise”,但是既然你谈到算法,我决定尝试一下(对不起,我对python不太熟悉)
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])
b = np.array([int])
#init 2nd array
for x in range (0,(a.size-1)):
b = np.append(b,0)
print (b)
#1st case
for x in range (2,(a.size)):
if (a[x-2]==1 & a[x-1]==1 & a[x]==1): #1-1-1
b[x] = 1
b[x-1] = 1
b[x-2] = 1
print (b)
#2nd case
for x in range (2,(b.size)):
if (b[x-2]==1 & b[x]==1): #1-0-1
if (b[x-1]==0): #sorry, i forget about logical op. in python
b[x-1] = 1
print (b)
#3rd case
for x in range (3,(b.size)):
if (b[x-3]==1 & b[x]==1): #1-0-0-1
if (b[x-2]==0 & b[x]-1==0):
b[x-1] = 1
b[x-2] = 1
#4th case
for x in range (4,(b.size)):
if (a[x-4]==1 & a[x-3]==1 & b[x]): #1-1-0-0-1
if (a[x-2]==0 & a[x]-1==0):
b[x-3] = 1
b[x-4] = 1
print (b)
我不确定这是否完全符合您的预期结果,但这里是:
[1 1 1 1 1 1 1 0 1 1 0 0 1 1 1 1 1 1 1 1 1 1 0]
答案 3 :(得分:1)
很多方法。我会将其拆分为分组, pply条件组和展平操作。像这样:
from itertools import groupby, starmap
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])
def condition(groups, key, newkey, minlen):
return [(newkey, l) if l < minlen and k == key else (k, l) for k, l in groups]
def flatten(groups):
return [k for g in starmap(lambda k, l: l * [k], groups) for k in g]
def group(l):
return [(k, len(list(v))) for k, v in groupby(l)]
res = group(flatten(condition(group(a), 1, 0, 3)))
# groups zeros at the beginning or the end never change to ones,
# no matter their length
res = flatten([res[0]] + condition(res[1:-1], 0, 1, 3) + [res[-1]])
print [bool(v) for v in res]