Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Check if there are 3 consecutive values in an array which are above some threshold

Tags:

python

numpy

Say I have a np.array like this:

a = [1, 3, 4, 5, 60, 43, 53, 4, 46, 54, 56, 78]

Is there a quick method to get the indices of all locations where 3 consecutive numbers are all above some threshold? That is, for some threshold th, get all x where this holds:

a[x]>th and a[x+1]>th and a[x+2]>th

Example: for threshold 40 and the list given above, x should be [4,8,9].

Many thanks.

like image 421
WangYang.Cao Avatar asked Jan 03 '23 01:01

WangYang.Cao


1 Answers

Approach #1

Use convolution on the mask of boolean array obtained after comparison -

In [40]: a # input array
Out[40]: array([ 1,  3,  4,  5, 60, 43, 53,  4, 46, 54, 56, 78])

In [42]: N = 3 # compare N consecutive numbers

In [44]: T = 40 # threshold for comparison

In [45]: np.flatnonzero(np.convolve(a>T, np.ones(N, dtype=int),'valid')>=N)
Out[45]: array([4, 8, 9])

Approach #2

Use binary_erosion -

In [77]: from scipy.ndimage.morphology import binary_erosion

In [31]: np.flatnonzero(binary_erosion(a>T,np.ones(N, dtype=int), origin=-(N//2)))
Out[31]: array([4, 8, 9])

Approach #3 (Specific case) : Small numbers of consecutive numbers check

For checking such a small number of consecutive numbers (three in this case), we can also slicing on the compared mask for better performance -

m = a>T
out = np.flatnonzero(m[:-2] & m[1:-1] & m[2:])

Benchmarking

Timings on 100000 repeated/tiled array from given sample -

In [78]: a
Out[78]: array([ 1,  3,  4,  5, 60, 43, 53,  4, 46, 54, 56, 78])

In [79]: a = np.tile(a,100000)

In [80]: N = 3

In [81]: T = 40

# Approach #3
In [82]: %%timeit
    ...: m = a>T
    ...: out = np.flatnonzero(m[:-2] & m[1:-1] & m[2:])
1000 loops, best of 3: 1.83 ms per loop

# Approach #1
In [83]: %timeit np.flatnonzero(np.convolve(a>T, np.ones(N, dtype=int),'valid')>=N)
100 loops, best of 3: 10.9 ms per loop

# Approach #2    
In [84]: %timeit np.flatnonzero(binary_erosion(a>T,np.ones(N, dtype=int), origin=-(N//2)))
100 loops, best of 3: 11.7 ms per loop
like image 105
Divakar Avatar answered Jan 05 '23 16:01

Divakar