[SciPy-user] Extrema finding

iCy-fLaME icy.flame.gm@gmail....
Thu Oct 9 11:20:08 CDT 2008


On Thu, Oct 9, 2008 at 1:21 PM, John Hunter <jdh2358@gmail.com> wrote:
> On Thu, Oct 9, 2008 at 6:44 AM, iCy-fLaME <icy.flame.gm@gmail.com> wrote:
>> I am trying to find a list of all maxima and minima, each for a given
>> (1D) numpy array. Anyone know of a quick way to do it?
>
>
>>
>> Ideally the function will return the extrema values and their
>> positions. Relatively simple function to implement in Python, but that
>> would be painfully slow. The typical data array I am looking at, has
>> approximately 500k elements of double precision float.
>
> I use the following to find the indices of extrema:
>
>
> def extrema_sampling(x, withend=False):
>    """
>    return the indices into the local maxima or minima of x
>    if withend, include the 0 and end points in the sampling
>    """
>    d = np.diff(x)
>    d2 = d[:-1]*d[1:]
>    ind = []
>    if withend:
>        ind.append(0)
>    ind.extend(np.nonzero(d2<0)[0]+1)
>    if withend and ind[-1]!=len(x)-1:
>        ind.append(len(x)-1)
>    return np.array(ind)

This is an excellent way of indexing extrema! Although it doesnt
return exactly what I wanted and it wont catch gradient changes to
zero.

Inspired by the above, I have come up with the following, hope it can
be of some use to others:


def extrema(x, max = True, min = True, strict = False, withend = False):
	"""
	This function will index the extrema of a given array x.
	
	Options:
		max		If true, will index maxima
		min		If true, will index minima
		strict		If true, will not index changes to zero gradient
		withend	If true, always include x[0] and x[-1]
	
	This function will return a tuple of extrema indexies and values
	"""
	
	# This is the gradient
	from numpy import zeros
	dx = zeros(len(x))
	from numpy import diff
	dx[1:] = diff(x)
	dx[0] = dx[1]
	
	# Clean up the gradient in order to pick out any change of sign
	from numpy import sign
	dx = sign(dx)
	
	# define the threshold for whether to pick out changes to zero gradient
	threshold = 0
	if strict:
		threshold = 1
		
	# Second order diff to pick out the spikes
	d2x = diff(dx)
	
	if max and min:
		d2x = abs(d2x)
	elif max:
		d2x = -d2x
	
	# Take care of the two ends
	if withend:
		d2x[0] = 2
		d2x[-1] = 2
	
	# Sift out the list of extremas
	from numpy import nonzero
	ind = nonzero(d2x > threshold)[0]
	
	return ind, x[ind]


More information about the SciPy-user mailing list