get index of the first block of at least n consecutive False values in boolean array

我是研究僧i 提交于 2021-02-07 13:54:11

问题


I have a numpy boolean array

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

I would like to get the index of the first time there are at n_at_least false values. For instance here

`n_at_least`=1 -> desired_index=1

`n_at_least`=3 -> desired_index=4

I have tried

np.cumsum(~w)

which does increase every time a False value is encountered. However, when True is encountered the counter is not starting from 0 again so I only get the total count of False elements rather than the count of the last consecutive ones.


回答1:


I think for this linear search operation a python implementation is ok. My suggestion looks like this:

def find_block(arr, n_at_least=1):
    current_index = 0
    current_count = 0
    for index, item in enumerate(arr):
         if item:
             current_count = 0
             current_index = index + 1
         else:
             current_count += 1
         if current_count == n_at_least:
             return current_index
    return None # Make sure this is outside for loop

Running this function yields the following outputs:

>>> import numpy
>>> w = numpy.array([True, False, True, True, False, False, False])
>>> find_block(w, n_at_least=1)
1
>>> find_block(w, n_at_least=3)
4
>>> find_block(w, n_at_least=4)
>>> # None



回答2:


Here's a vectorized solution that finds the start, stop indices and hence lengths of islands of zeros and finally uses argmax to get the starting index of the first island satisfying the criteria of zeros count being >= n -

def first_occ_index(w, n):
    idx = np.flatnonzero(np.r_[True, w, True])
    lens = np.diff(idx) - 1
    return idx[(lens >= n).argmax()]

Sample run -

In [107]: w
Out[107]: array([ True, False,  True,  True, False, False, False])

In [108]: first_occ_index(w, n=1)
Out[108]: 1

In [109]: first_occ_index(w, n=3)
Out[109]: 4



回答3:


I think you're falling into the numpy trap of only wanting to use numpy functions. What's wrong with python? This solution is O(n)

def f(array, n_at_least):
    curr_found_false = 0
    curr_index = 0
    for index, elem in enumerate(array):
        if not elem:
            if curr_found_false == 0:
                curr_index = index
            curr_found_false += 1
            if curr_found_false == n_at_least:
                return curr_index
        else:
            curr_found_false = 0

Outputs

w=np.array([True,False,True,True,False,False,False])
f(w, 1)
# --> 1
f(w, 3)
# --> 4



回答4:


Here is an O(n) numpy solution:

>>> def first_consec(A, n):
...     A = np.r_[True, A, True]
...     switch, = np.where(A[:-1]!=A[1:])
...     runs = switch[1::2] - switch[::2]
...     idx = np.argmax(runs >= n)
...     if runs[idx] < n:
...         return None
...     return switch[2*idx]
... 
>>> first_consec(w, 4)
>>> first_consec(w, 3)
4
>>> first_consec(w, 2)
4
>>> first_consec(w, 1)
1



回答5:


It should work this way:

def n_at_least(n):
    for i in range(len(w)):
         if not any(w[i:i+n]):
             return i

However I don't know if there is a better way...




回答6:


This is one way using a generator expression with slicing:

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

n = 2
val = False

res = next((i for i, j in enumerate(w[k:k+n] for k in range(len(w)-n+1)) \
            if np.all(j==val)), None)

# 4


来源:https://stackoverflow.com/questions/49693770/get-index-of-the-first-block-of-at-least-n-consecutive-false-values-in-boolean-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!