Numpy: detecting serial 1 in an array

I want to detect consecutive intervals of 1 in a numpy array. In fact, I want to first determine if an element in the array is in the range of at least three 1. For example, we have the following array 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]) 

Then the next 1 bold are elements that satisfy the requirement.

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

Further, if two intervals of 1 are separated by no more than two 0, then two intervals constitute a longer interval. Thus, the specified array is characterized as

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

In other words, for the original array as input, I want the result to be as follows:

  [True, True, True, True, True, True, True, False, False, False, False, False, True, True, True, True, True, True, True, True, True, True, False] 

I was thinking of an algorithm to implement this function, but everything I came up with seems complicated. Therefore, I would like to know the best ways to implement this - it would be very helpful if someone can help me.

Update:

I apologize for not asking a question. I want to identify 3 or more consecutive 1s in the array as span 1, and any two spans 1 with one or two 0s between them are identified along with separating 0s as one long span. My goal can be understood as follows: if there is only one or two 0 between flights 1, I consider these 0 errors and should be fixed as 1.

@ ritesht93 provided an answer that almost gives what I want. However, the current answer does not determine the case when there are three intervals of 1, which are separated by 0, which should be identified as one separate interval. For example, for an array

  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]) 

we should get a conclusion

  [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] 

Update 2:

I was very inspired and found that the regex-based algorithm is the easiest to implement and understand, although I'm not sure about the effectiveness compared to other methods. In the end, I used the following method.

  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 

which identified intervals 1

  0ccc0ccc00cccc00100ccccc0 

and then connect the gaps with 1

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

which gives

  0ccccccccccccc00100ccccc0 

The end result is given

  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]) 
+5
source share
4 answers

Instead of solving the usual way of looping and maintaining counts, we can convert all 0 and 1 to one line and replace the regular expression with another char say 2 . Once this is done, we will split the string again and check bool() for each char.

 >>> 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] >>> 

All operations take place here:

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

where he is looking for a continuous occurrence of 3 or more than 1, followed by no more than 2 0, i.e. 1 or 2 0, and then 3 or more than 1 and replaces the entire line with the same length of 2 lines (2 is used because bool(2) True ). You can also use the tolist() method in NumPy to get a list from a NumPy array as follows: np.array([1,2, 3, 4, 5, 6]).tolist()

Edit 1 : after changing the question, here is the updated answer:

 >>> 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] >>> 

Amend 2 FINAL ANSWER :

 >>> 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] >>> 
+1
source

We could solve this problem with a combination of binary dilation and erosion to go through the first step, and then binary closing to get the final output, for example:

 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 

Run Examples

Case No. 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) 

Case No. 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) 
+2
source

I know this is not "python-wise", but since you are talking about an algorithm, I decided to try it (sorry, I'm not very familiar with 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) 

I'm not sure that this is exactly your expected result, but here it is:
[1 1 1 1 1 1 1 0 1 1 0 0 1 1 1 1 1 1 1 1 1 1 1 0]

+1
source

Many ways to do this. I would divide it into a grouping, apply conditions to groups and smoothing operations. For instance:

 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] 
+1
source

Source: https://habr.com/ru/post/1259023/


All Articles