在 numpy 数组中取每个条目的最小值 +- 10 行

Posted

技术标签:

【中文标题】在 numpy 数组中取每个条目的最小值 +- 10 行【英文标题】:Taking minimum value of each entry +- 10 rows either side in numpy array 【发布时间】:2017-12-15 09:21:03 【问题描述】:

我有一个 3d numpy 数组,并希望生成一个二级数​​组,其中包含每个值的最小值以及正上方 10 行和正下方 10 行中的值(即每个条目是 21 个值中的最小值)每个二维数组。

我一直在尝试使用“numpy.clip”来处理数组的边缘——这里取最小值的值的范围应该简单地减少到顶部/底部的值的 10大批。我认为像 'scipy.signal.argrelmin' 这样的东西似乎是我所追求的。

到目前为止,这是我的代码,绝对不是最好的方法:

import numpy as np

array_3d = np.random.random_integers(50, 80, (3, 50, 18))
minimums = np.zeros(array_3d.shape)

for array_2d_index in range(len(array_3d)):
    for row_index in range(len(array_3d[array_2d_index])):
        for col_index in range(len(array_3d[array_2d_index][row_index])):
            minimums[array_2d_index][row_index][col_index] = min(array_3d[array_2d_index][np.clip(row_index-10, 0, 49):np.clip(row_index+10, 0, 49)][col_index])

我认为的主要问题是,这是从每个条目两侧的列而不是行中获取最小值,这会导致索引错误。

不胜感激,谢谢。

【问题讨论】:

【参考方案1】:

方法#1

这是np.lib.stride_tricks.as_strided 的一种方法-

def strided_3D_axis1(array_3d, L):
    s0,s1,s2 = array_3d.strides
    strided = np.lib.stride_tricks.as_strided 
    m,n,r = array_3d.shape
    nL = n-L+1
    return strided(array_3d, (m,nL,L,r),(s0,s1,s1,s2))

out = strided_3D_axis1(array_3d, L=21).min(axis=-2)

示例运行 -

1) 输入:

In [179]: array_3d
Out[179]: 
array([[[73, 65, 51, 76, 59],
        [74, 57, 75, 53, 70],
        [60, 74, 52, 54, 60],
        [54, 52, 62, 75, 50],
        [68, 56, 68, 63, 77]],

       [[62, 70, 60, 79, 74],
        [70, 68, 50, 74, 57],
        [63, 57, 69, 65, 54],
        [63, 63, 68, 58, 60],
        [70, 66, 65, 78, 78]]])

2) 跨步视图:

In [180]: strided_3D_axis1(array_3d, L=3)
Out[180]: 
array([[[[73, 65, 51, 76, 59],
         [74, 57, 75, 53, 70],
         [60, 74, 52, 54, 60]],

        [[74, 57, 75, 53, 70],
         [60, 74, 52, 54, 60],
         [54, 52, 62, 75, 50]],

        [[60, 74, 52, 54, 60],
         [54, 52, 62, 75, 50],
         [68, 56, 68, 63, 77]]],


       [[[62, 70, 60, 79, 74],
         [70, 68, 50, 74, 57],
         [63, 57, 69, 65, 54]],

        [[70, 68, 50, 74, 57],
         [63, 57, 69, 65, 54],
         [63, 63, 68, 58, 60]],

        [[63, 57, 69, 65, 54],
         [63, 63, 68, 58, 60],
         [70, 66, 65, 78, 78]]]])

3) 基于min 的跨步视图:

In [181]: strided_3D_axis1(array_3d, L=3).min(axis=-2)
Out[181]: 
array([[[60, 57, 51, 53, 59],
        [54, 52, 52, 53, 50],
        [54, 52, 52, 54, 50]],

       [[62, 57, 50, 65, 54],
        [63, 57, 50, 58, 54],
        [63, 57, 65, 58, 54]]])

方法 #2

这是另一个 broadcasting 在沿第二个轴创建所有滑动索引时 -

array_3d[:,np.arange(array_3d.shape[1]-L+1)[:,None] + range(L)].min(-2)

方法#3

这是另一个使用Scipy's 1D minimum filter -

from scipy.ndimage.filters import minimum_filter1d as minf

L = 21
hL = (L-1)//2
out = minf(array_3d,L,axis=1)[:,hL:-hL]

运行时测试 -

In [231]: array_3d = np.random.randint(50, 80, (3, 50, 18))

In [232]: %timeit strided_3D_axis1(array_3d, L=21).min(axis=-2)
10000 loops, best of 3: 54.2 µs per loop

In [233]: %timeit array_3d[:,np.arange(array_3d.shape[1]-L+1)[:,None] + range(L)].min(-2)
10000 loops, best of 3: 81.3 µs per loop

In [234]: L = 21
     ...: hL = (L-1)//2
     ...: 

In [235]: %timeit minf(array_3d,L,axis=1)[:,hL:-hL]
10000 loops, best of 3: 32 µs per loop

【讨论】:

谢谢。我已经测试了这些,发现如果最小值(例如 randint 中的 50)位于数组的边缘(例如底行),那么正上方的 10 个值不等于 50,而是更高。 @JGraham353 使用所有三种方法? 另外,'L' 应该设置为 11 以只允许值的范围是给定值的正上方 10 行和正下方的 10 行? @JGraham353 所以,对于我们不会有 10 行及以下窗口的边缘元素,您要考虑尽可能多的可用,对吗?例如,对于最后一行,我们将只拥有该行本身及其上方的 10 行,即它只会尝试在 11 行中找到可用的最小值。这是一个正确的假设吗? @JGraham353 然后,只需使用没有切片的最后一种方法:minf(array_3d,21,axis=1)

以上是关于在 numpy 数组中取每个条目的最小值 +- 10 行的主要内容,如果未能解决你的问题,请参考以下文章

字典条目都是一样的

对numpy数组中的每个第n个条目进行二次采样

java如何在数组中取最大值和最小值

如何有效地找到 NumPy 中平滑多维数组的局部最小值?

具有 1 位条目的 numpy 布尔数组

在 1D-NumPy 数组中查找奇异值/局部最大值/最小值集(再次)