在一个numpy数组中找到满足某些条件的长度为N的范围

4
我有一个表示测量曲线的(numpy)数组。我正在寻找第一个索引i,在此之后连续的N个元素满足某些条件,例如,位于特定范围内。用伪代码描述,我正在寻找最小的i,使得:
lower_bound < measurement[i:i+N] < higher_bound

对于范围内的所有元素都满足。

当然,我可以执行以下操作:

for i in xrange(len(measurement) - N):
    test_vals = measurement[i:i + N]
    if all([True if lower_bound < x < higher_bound else False for x in test_vals]):
        return i

对于每个 i,我总是要比较 N 个值,这是非常低效的。有没有一种最符合Python风格的方法来实现这个?Numpy是否有一些内置功能来解决这个问题?

编辑: 根据请求,我提供一些示例输入数据

a = [1,2,3,4,5,5,6,7,8,5,4,5]
lower_bound = 3.5
upper_bound = 5.5 
N = 3

应返回3,因为从a [3]开始,至少有3个值处于边界内。

请给我们一些样本输入数据以便操作? - Divakar
作为第一次优化,当x不在范围内时,您可以从measurement[i+index(x)+1]开始下一轮test_vals测试。 - VirgileD
3个回答

3

一个 NumPythonic 的矢量化解决方案是,创建一个沿着输入数组 measurement 整个长度的滑动窗口堆叠为一个 2D 数组,然后使用这些索引在数组中进行索引以形成 measurement 的 2D 数组版本。接下来,在边界检查之后一次性查找所有成功的边界,使用 np.all(..axis=1)。最后选择第一个成功的索引作为输出。实现大致如下-

m2D = measurement[np.arange(N) + np.arange(len(measurement)-N+1)[:,None]]
np.nonzero(np.all((lower_bound < m2D) & (higher_bound > m2D),axis=1))[0][0]

示例运行 -

In [1]: measurement = np.array([1,2,3,4,5,5,6,7,8,5,4,5])
   ...: lower_bound = 3.5
   ...: higher_bound = 5.5 
   ...: N = 3
   ...: 

In [2]: m2D = measurement[np.arange(N) + np.arange(len(measurement)-N+1)[:,None]]

In [3]: m2D # Notice that is a 2D array (shifted) version of input
Out[3]: 
array([[1, 2, 3],
       [2, 3, 4],
       [3, 4, 5],
       [4, 5, 5],
       [5, 5, 6],
       [5, 6, 7],
       [6, 7, 8],
       [7, 8, 5],
       [8, 5, 4],
       [5, 4, 5]])

In [4]: np.nonzero(np.all((lower_bound < m2D) & (higher_bound > m2D),axis=1))[0][0]
Out[4]: 3

谢谢,这正是我在寻找的! - stebu92

2
如果a的长度为M,这里有一个O(M)的解决方案。
locations=(lower_bound<a) & (a<upper_bound)
cum=locations.cumsum()
lengths=np.roll(cum,-N)-cum==N
result=lengths.nonzero()[0][0]+1

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接