【问题标题】:Find the first index for which an array goes below a certain threshold (and stay below for some time)找到数组低于某个阈值的第一个索引(并保持低于一段时间)
【发布时间】:2019-02-10 20:28:36
【问题描述】:

A 为一维numpy 数组,阈值t,窗口长度K

如何找到最小索引j,使得A[j:j+K] < t(即A第一次在宽度为K的完整窗口低于阈值 )。

我用循环尝试过(未完成的)事情,但它似乎远非最佳,我想也许有一个聪明的“numpy 方式”来做到这一点。


旁注:我们想要测试我们是否低于阈值在某个窗口长度内而不是实际值,这对于避免开/关/开/关/开/关很有用阈值附近的伪影(另请参阅Hysteresis“有意将滞后添加到电子电路中,以防止不必要的快速切换 [...] 补偿开关中的触点反弹或电信号中的噪声。” em>)。

【问题讨论】:

  • next(j for j in range(len(A)-K) if all(A[j:j+K] < t), None))?
  • @pault 是的,可能就是这样!但如果数组很长,我怀疑为所有 j in range(len(A)-K) 评估 all(A[j:j+K] < t) 可能需要很长时间来计算
  • Divakar 的解决方案要快得多,但 all 会短路,您不会检查所有 j,因为我们使用的是 next

标签: python arrays numpy threshold windowing


【解决方案1】:

方法#1

我们可以使用1D convolution -

np.flatnonzero(np.convolve(A<t, np.ones(K,dtype=int))==K)[0]-K+1

这个想法是在与阈值比较后得到布尔数组,然后运行一个1D卷积,其长度与window相同,填充1s。这给了我们每个滑动窗口的总和。所以,总和为K 的所有窗口都是我们所追求的。使用flatnonzero 获取有效窗口的起始索引。最后选择第一个。

方法#2

binary-erosion -

from scipy.ndimage.morphology import binary_erosion

np.flatnonzero(binary_erosion(A<t, np.ones(K), origin=-(K//2)))[0]

这运行一个长度与window 相同的滑动内核,并依次侵蚀掉所有没有window 长度True 的窗口,留下有效的窗口。同样,使用flatnonzero 获取索引,最后选择第一个。我们需要使用带有二进制侵蚀的 arg origin,以便我们选择开始。

方法#3

这是另一个寻找岛屿的方法 -

# Get mask of valid elements with comparison against thresh
mask = np.r_[False,A<t,False]

# Get indices of starts and ends for the valid islands
idx = np.flatnonzero(mask[:-1] != mask[1:])
start,stop = idx[::2],idx[1::2]

# Get the island lengths and check for lengths >=K and mask  start indices
# and select the first one among them
out = start[(stop - start)>=K][0]

【讨论】:

  • 为什么要检查&gt;=K 而不是==K?对于 1 内核和 0 和 1 数组(或 False 和 True),卷积项不应超过 K,对吗?我知道这只是吹毛求疵。
  • @ChristophTerasa 好点!虽然它不会改变性能(我认为)。已编辑。
  • @Basj,将所有函数调用分开,并在一个简单的示例中一个接一个地尝试它们(例如AA.size=12K=3)。然后你应该能够确定所有部分的作用。
  • @Basj 添加了一些解释。
  • 非常感谢@Divakar 这个非常有趣的答案。现在,我将使用方法#2,这是我理解的最快的一种!
猜你喜欢
  • 2018-03-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多