【问题标题】:Finding turning points of an Array in python在python中查找数组的转折点
【发布时间】:2013-11-25 00:09:36
【问题描述】:

例如,如果我有一个数组:

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

可以看出有4个转折点。 (在 A[4]、A[6]、A[13]、A[17])

如何使用python返回转折点数?

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)

目前,这个系统是有缺陷的,而且肯定不是很优雅。有什么想法吗?

【问题讨论】:

    标签: python arrays python-2.7 minima


    【解决方案1】:

    如果你有 numpy:

    def turningpoints(lst):
        dx = np.diff(lst)
        return np.sum(dx[1:] * dx[:-1] < 0)
    

    或非 numpy 等效版本:

    def turningpoints(lst):
        dx = [x - y for x, y in zip(lst[1:], lst[:-1])]
        return sum(dx1 * dx2 < 0 for dx1, dx2 in zip(dx[1:], dx[:-1]))
    

    而且只是为了爱单行:

    def turningpoints(lst):
        return sum(x0*x1 + x1*x2 < x1*x1 + x0*x2 for x0, x1, x2 in zip(lst[2:], lst[1:-1], lst[:-2]))
    

    但是这个可读性可以说是降低了:)

    【讨论】:

    • 第二个:TypeError: 'generator' object is not subscriptable。大概dx应该是一个列表。
    【解决方案2】:

    我知道这是一个老问题,但我也遇到了同样的问题,正如 Cardin 在 Malvolio's answer 的 cmets 中所说,答案无法处理具有相同值的连续点,如 [1, 2, 3, 4, 4, 4, 3, 2, 1]。我的实现可以处理这个问题。

    虽然它返回两个列表,其中包含最小和最大转折点的索引。

    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
    

    为了正确回答问题,转折点的数量计算如下:

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

    示例

    【讨论】:

      【解决方案3】:

      你想多了。 “转折点”是指高于或低于两边的点。

      def turningpoints(x):
        N=0
        for i in range(1, len(x)-1):
           if ((x[i-1] < x[i] and x[i+1] < x[i]) 
               or (x[i-1] > x[i] and x[i+1] > x[i])):
             N += 1
        return N
      
      >>> turningpoints([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6])
      4
      

      【讨论】:

      • 此解决方案不起作用。试试 [5, 6, 7, 7, 7, 6, 5]
      • @Cardin,你是说这有两个转折点而不是零?那么 [5, 6, 7, 7, 7, 8, 9] 呢?那是零还是两个(或其他)?
      • 如,该序列有 1 个转折点,但您的算法无法检测到它,因为它假设方向变化必须立即发生。
      • 你新发布的序列没有任何转折点,因为它是一个静止点。
      • @Cardin -- 有没有我遗漏的官方定义?
      【解决方案4】:
      >>> def turns(L):
      ...     answer, delta = 0, -1 if L[1]<L[0] else 1
      ...     i = 2
      ...     while i < len(L):
      ...             d = -1 if L[i]<L[i-1] else 1
      ...             if d != delta:
      ...                     answer += 1
      ...                     delta = d
      ...             i += 1
      ...     return answer
      ... 
      >>> L = [0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6]
      >>> turns(L)
      4
      

      【讨论】:

        【解决方案5】:
        def group_in_threes(slicable):
            for i in range(len(slicable)-2):
                yield slicable[i:i+3]
        
        def turns(L):
            for index, three in enumerate(group_in_threes(L)):
                if (three[0] > three[1] < three[2]) or (three[0] < three[1] > three[2]):
                    yield index + 1
        
        >>> list(turns([0,2,3,4,5,2,1,2,3,4,5,6,7,8,7,6,5,4,5,6]))
        [4, 6, 13, 17]
        >>> len(_)
        4
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2018-01-21
          • 2020-07-05
          • 2018-04-11
          • 2012-09-08
          • 1970-01-01
          • 1970-01-01
          • 2018-02-01
          相关资源
          最近更新 更多