- A+

I would like to have a function that can detect where the local maxima/minima are in an array (even if there is a set of local maxima/minima). Example:

Given the array

`test03 = np.array([2,2,10,4,4,4,5,6,7,2,6,5,5,7,7,1,1]) `

I would like to have an output like:

`set of 2 local minima => array[0]:array[1] set of 3 local minima => array[3]:array[5] local minima, i = 9 set of 2 local minima => array[11]:array[12] set of 2 local minima => array[15]:array[16] `

As you can see from the example, not only are the singular values detected but, also, sets of local maxima/minima.

I know in this question there are a lot of good answers and ideas, but none of them do the job described: some of them simply ignore the extreme points of the array and all ignore the sets of local minima/maxima.

Before asking the question, I wrote a function by myself (a newbie implementation, I am sorry) that does exactly what I described above (the function is at the end of this question).

I am also sure that is NOT the best way to work with Python. Are there builtin functions, APIs, libraries, etc. that I can use? Any other function suggestion? A one-line instruction?

`def local_min(a): candidate_min=0 for i in range(len(a)): # Controlling the first left element if i==0 and len(a)>=1: # If the first element is a singular local minima if a[0]<a[1]: print("local minima, i = 0") # If the element is a candidate to be part of a set of local minima elif a[0]==a[1]: candidate_min=1 # Controlling the last right element if i == (len(a)-1) and len(a)>=1: if candidate_min > 0: if a[len(a)-1]==a[len(a)-2]: print("set of " + str(candidate_min+1)+ " local minima => array["+str(i-candidate_min)+"]:array["+str(i)+"]") if a[len(a)-1]<a[len(a)-2]: print("local minima, i = " + str(len(a)-1)) # Controlling the other values in the middle of the array if i>0 and i<len(a)-1 and len(a)>2: # If a singular local minima if (a[i]<a[i-1] and a[i]<a[i+1]): print("local minima, i = " + str(i)) # print(str(a[i-1])+" > " + str(a[i]) + " < "+str(a[i+1])) #debug # If it was found a set of candidate local minima if candidate_min >0: # The candidate set IS a set of local minima if a[i] < a[i+1]: print("set of " + str(candidate_min+1)+ " local minima => array["+str(i-candidate_min)+"]:array["+str(i)+"]") candidate_min = 0 # The candidate set IS NOT a set of local minima elif a[i] > a[i+1]: candidate_min = 0 # The set of local minima is growing elif a[i] == a[i+1]: candidate_min = candidate_min + 1 # It never should arrive in the last else else: print("Something strange happen") return -1 # If there is a set of candidate local minima (first value found) if (a[i]<a[i-1] and a[i]==a[i+1]): candidate_min = candidate_min + 1 `

Note: I tried to enrich the code with some comment to understand what I would like to do. I know that the function that I propose is not clean and just prints the results that can be stored and returned at the end. It was written to give an example. The algorithm I propose should be O(n).

**UPDATE:**

Somebody was suggesting to import `from scipy.signal import argrelextrema`

and use the function like:

`def local_min_scipy(a): minima = argrelextrema(a, np.less_equal)[0] return minima def local_max_scipy(a): minima = argrelextrema(a, np.greater_equal)[0] return minima `

To have something like that is what I am really looking for. However, it doesn't work properly when the sets of local minima/maxima have more than two values. For example:

`test03 = np.array([2,2,10,4,4,4,5,6,7,2,6,5,5,7,7,1,1]) print(local_max_scipy(test03)) `

The output is:

`[ 0 2 4 8 10 13 14 16] `

Of course in `test03[4]`

I have a minimum and not a maximum. How do I fix this behavior? (I don't know if this is another question or if this is the right place where to ask it.)

A full vectored solution:

`test03 = np.array([2,2,10,4,4,4,5,6,7,2,6,5,5,7,7,1,1]) # Size 17 extended = np.empty(len(test03)+2) # Rooms to manage edges, size 19 extended[1:-1] = test03 extended[0] = extended[-1] = np.inf flag_left = extended[:-1] <= extended[1:] # Less than successor, size 18 flag_right = extended[1:] <= extended[:-1] # Less than predecessor, size 18 flagmini = flag_left[1:] & flag_right[:-1] # Local minimum, size 17 mini = np.where(flagmini)[0] # Indices of minimums spl = np.where(np.diff(mini)>1)[0]+1 # Places to split result = np.split(mini, spl) `

`result`

:

`[0, 1] [3, 4, 5] [9] [11, 12] [15, 16] `