在 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 行的主要内容,如果未能解决你的问题,请参考以下文章