代码之家  ›  专栏  ›  技术社区  ›  ptomato

如何有效地找到光滑多维数组在numpy中的局部极小值?

  •  10
  • ptomato  · 技术社区  · 14 年前

    假设我有一个numpy数组,其中包含对连续可微函数的计算,我想找到局部极小值。没有噪音,所以每一个值低于所有相邻点的值的点都符合我对局部最小值的标准。

    我有以下列表理解,它适用于二维数组,忽略边界上的潜在极小值:

    import numpy as N
    
    def local_minima(array2d):
        local_minima = [ index 
                         for index in N.ndindex(array2d.shape)
                         if index[0] > 0
                         if index[1] > 0
                         if index[0] < array2d.shape[0] - 1
                         if index[1] < array2d.shape[1] - 1
                         if array2d[index] < array2d[index[0] - 1, index[1] - 1]
                         if array2d[index] < array2d[index[0] - 1, index[1]]
                         if array2d[index] < array2d[index[0] - 1, index[1] + 1]
                         if array2d[index] < array2d[index[0], index[1] - 1]
                         if array2d[index] < array2d[index[0], index[1] + 1]
                         if array2d[index] < array2d[index[0] + 1, index[1] - 1]
                         if array2d[index] < array2d[index[0] + 1, index[1]]
                         if array2d[index] < array2d[index[0] + 1, index[1] + 1]
                       ]
        return local_minima
    

    然而,这是相当缓慢的。我还想让它适用于任何数量的维度。例如,是否有一种简单的方法可以在任何维度的数组中获取点的所有相邻点?或者我是完全错误地处理这个问题?我应该用吗 numpy.gradient() 相反?

    2 回复  |  直到 14 年前
        1
  •  16
  •   Community CDub    7 年前

    对于任意维的数组,可以找到局部极小值的位置。 使用 Ivan detect_peaks function ,稍作修改:

    import numpy as np
    import scipy.ndimage.filters as filters
    import scipy.ndimage.morphology as morphology
    
    def detect_local_minima(arr):
        # https://stackoverflow.com/questions/3684484/peak-detection-in-a-2d-array/3689710#3689710
        """
        Takes an array and detects the troughs using the local maximum filter.
        Returns a boolean mask of the troughs (i.e. 1 when
        the pixel's value is the neighborhood maximum, 0 otherwise)
        """
        # define an connected neighborhood
        # http://www.scipy.org/doc/api_docs/SciPy.ndimage.morphology.html#generate_binary_structure
        neighborhood = morphology.generate_binary_structure(len(arr.shape),2)
        # apply the local minimum filter; all locations of minimum value 
        # in their neighborhood are set to 1
        # http://www.scipy.org/doc/api_docs/SciPy.ndimage.filters.html#minimum_filter
        local_min = (filters.minimum_filter(arr, footprint=neighborhood)==arr)
        # local_min is a mask that contains the peaks we are 
        # looking for, but also the background.
        # In order to isolate the peaks we must remove the background from the mask.
        # 
        # we create the mask of the background
        background = (arr==0)
        # 
        # a little technicality: we must erode the background in order to 
        # successfully subtract it from local_min, otherwise a line will 
        # appear along the background border (artifact of the local minimum filter)
        # http://www.scipy.org/doc/api_docs/SciPy.ndimage.morphology.html#binary_erosion
        eroded_background = morphology.binary_erosion(
            background, structure=neighborhood, border_value=1)
        # 
        # we obtain the final mask, containing only peaks, 
        # by removing the background from the local_min mask
        detected_minima = local_min - eroded_background
        return np.where(detected_minima)       
    

    可以这样使用:

    arr=np.array([[[0,0,0,-1],[0,0,0,0],[0,0,0,0],[0,0,0,0],[-1,0,0,0]],
                  [[0,0,0,0],[0,-1,0,0],[0,0,0,0],[0,0,0,-1],[0,0,0,0]]])
    local_minima_locations = detect_local_minima(arr)
    print(arr)
    # [[[ 0  0  0 -1]
    #   [ 0  0  0  0]
    #   [ 0  0  0  0]
    #   [ 0  0  0  0]
    #   [-1  0  0  0]]
    
    #  [[ 0  0  0  0]
    #   [ 0 -1  0  0]
    #   [ 0  0  0  0]
    #   [ 0  0  0 -1]
    #   [ 0  0  0  0]]]
    

    这表明最小值出现在指数[0,0,3]、[0,4,0]、[1,1,1]和[1,3,3]处:

    print(local_minima_locations)
    # (array([0, 0, 1, 1]), array([0, 4, 1, 3]), array([3, 0, 1, 3]))
    print(arr[local_minima_locations])
    # [-1 -1 -1 -1]
    
        2
  •  4
  •   eumiro    14 年前

    尝试此二维:

    import numpy as N
    
    def local_minima(array2d):
        return ((array2d <= N.roll(array2d,  1, 0)) &
                (array2d <= N.roll(array2d, -1, 0)) &
                (array2d <= N.roll(array2d,  1, 1)) &
                (array2d <= N.roll(array2d, -1, 1)))
    

    这将返回一个类似array2d的数组,其中包含本地minima(四个邻居)所在的true/false。