Finding turning points of an Array in python

user2984189 picture user2984189 · Nov 12, 2013 · Viewed 11.1k times · Source

If I for example have an array:

A = (0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6)

It can be seen that there are 4 turning points. (at A[4],A[6], A[13], A[17])

How can I use python to return the number of turning points?

import numpy as np
import scipy.integrate as SP
import math

def turningpoints(A):
    print A
    N = 0
    delta = 0
    delta_prev = 0
    for i in range(1,19):
        delta = A[i-1]-A[i]       #Change between elements
        if delta < delta_prev:    #if change has gotten smaller
            N = N+1               #number of turning points increases
        delta_prev = delta        #set the change as the previous change
    return N

if __name__ == "__main__":
    A  = np.array([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6])
    print turningpoints(A)

Currently, this system is flawed and certainly not very elegant. Any ideas?

Answer

Timo picture Timo · Jan 20, 2018

I know it's an old question, but I just had the same problem and as Cardin stated in the comments of Malvolio's answer, the answer cannot handle successive points with the same value like [1, 2, 3, 4, 4, 4, 3, 2, 1]. My implementation can handle this problem.

Although, it returns two lists with the indices of the minimum and maximum turning points.

def turning_points(array):
    ''' turning_points(array) -> min_indices, max_indices
    Finds the turning points within an 1D array and returns the indices of the minimum and 
    maximum turning points in two separate lists.
    '''
    idx_max, idx_min = [], []
    if (len(array) < 3): 
        return idx_min, idx_max

    NEUTRAL, RISING, FALLING = range(3)
    def get_state(a, b):
        if a < b: return RISING
        if a > b: return FALLING
        return NEUTRAL

    ps = get_state(array[0], array[1])
    begin = 1
    for i in range(2, len(array)):
        s = get_state(array[i - 1], array[i])
        if s != NEUTRAL:
            if ps != NEUTRAL and ps != s:
                if s == FALLING: 
                    idx_max.append((begin + i - 1) // 2)
                else:
                    idx_min.append((begin + i - 1) // 2)
            begin = i
            ps = s
    return idx_min, idx_max

To correctly answer the question, the number of turning points is then computed as:

sum(len(x) for x in turning_points(X))

Example

enter image description here