【问题标题】:How to extract subarrays from an array based on threshold values in python?如何根据python中的阈值从数组中提取子数组?
【发布时间】:2019-07-26 17:18:50
【问题描述】:

我有一个 numpy 数组的形式:

a = numpy.array([0,2,2,3,4,2,5,5,6,2,5,6,4,4,2,3,1,7,7,2,3,3,4,1,8,9,8,8])
threshold = 4
threshold_seq_len = 5
subarray_seq_len = 4

我希望实现的输出是

b =[array([5,5,6,2,5,6]), array([8,9,8,8])]

我想根据条件提取子数组:

1) 子数组应根据小于或等于 阈值 的值序列进行拆分。在上述情况下,第一个子数组([5,5,6,2,5,6]) 出现在序列[0,2,2,3,4,2] 之后,所有子数组都小于或等于阈值 4。

2) 阈值序列应至少与 threshold_seq_len 一样长,否则它们将只是子数组的一部分。请注意,value '2' 存在于第一个子数组中,因为它是单个出现的 (length =1)

3) 子数组本身应至少与 subarray_seq_len 一样长。例如,索引 17 和 18 处的值各为 7,但自 length<4 以来不考虑它们。

对于上下文,数组表示音频文件中的振幅,我正在尝试根据所描述的逻辑提取可行的非静音候选。

什么是有效实现这一目标的pythonic方法?

我已经尝试过Extract subarrays of numpy array whose values are above a threshold中描述的方法。

问题是,这个问题似乎是我的问题(threshold_seq_len=1, subarray_seq_len=1) 的一个具体案例,因为该任务仅涉及根据阈值的出现来拆分一个数组。我一直在尝试概括它,但到目前为止都失败了。

【问题讨论】:

  • 谢谢@Divakar 有没有办法不将此作为后处理步骤?时间是关键。
  • @Divakar 这将过滤掉标准 2 中的 2
  • 这是一个有效的子数组吗? [5,2,5,2,6,2,5,2,6]
  • @Ardweaden 是一个非常不受欢迎的边缘案例,但根据我的给定逻辑,它是一个公平的候选人。
  • 有了threshold_seq_len = 5,那不应该只有一个子数组吗?

标签: python numpy


【解决方案1】:

这是一种方法-

from scipy.ndimage.morphology import binary_closing

def filter_ar(a, threshold, threshold_seq_len, subarray_seq_len):
    # Mask wrt threshold
    m0 = np.r_[False,a>threshold,False]

    # Close "holes", those one-off lesser than thresh elements
    k = np.ones(2,dtype=bool)
    m = binary_closing(m0,k)

    # Get initial start, stop indices
    idx = np.flatnonzero(m[:-1] != m[1:])
    s0,s1 = idx[::2],idx[1::2]

    # Masks based on subarray_seq_len, threshold_seq_len
    mask1 = (s1-s0)>=subarray_seq_len
    mask2 = np.add.reduceat(m0,s0) >= threshold_seq_len

    # Get combined one after looking for first sequence that has threshold_seq_len
    # elements > threshold
    mask1[mask2.argmax():] &= True

    # Get valid start,stop indices and then split input array 
    starts,ends = s0[mask1],s1[mask1]
    out = [a[i:j] for (i,j) in zip(starts,ends)]
    return out

【讨论】:

    【解决方案2】:

    这确实适用于您的示例,但我无法避免列表理解。另外,我还没有检查这是否比简单地遍历列表要慢...(可能)

    b = np.where(a > threshold)[0]
    d = np.where(np.diff(b) >= threshold_seq_len)[0]
    e = np.split(b,d+1)
    
    subarrays = [a[i[0]:i[-1]+1] for i in e if (i[-1]-i[0] + 1) >= subarray_seq_len]
    

    【讨论】:

    • threshold_seq_len 是阈值的长度。 subarray_seq_len 是给候选人自己的。我编辑了示例以更清楚地说明差异。
    • 对不起,我很愚蠢。我还是不明白。我这与高于阈值的两个连续值之间低于阈值的值的数量有关吗?在这一点上,我只是要求理解,如果 Divakar 的代码有效,那它就无关紧要了。
    • 没有愚蠢的问题。查看示例中的第一个子数组 ([5,5,6,2,5,6])。它发生在小于或等于阈值的 6 个连续值之后(每个值小于/等于值 4)。因此长度 (=6) 是 > threshold_seq_len (=5)。另一方面,索引 16 和 17 处的值都是 >*threshold* 并且也出现在 threshold_seq_len 个连续值之后,但由于子数组 (=2) 本身的长度为 subarray_seq_len (=4)。希望这更清楚?很高兴进一步解释。
    • 现在清晰多了!谢谢你的解释。最后一个问题:既然 5,5,6,2,5,6 和 7,7 之间只有一个 4 的序列,为什么这两个 7 不属于第一个子数组?
    • 好点。编辑示例,现在它们之间有 5 个序列(它之前工作,但我忘记在第一次编辑后添加值)。
    猜你喜欢
    • 2017-09-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-25
    • 1970-01-01
    相关资源
    最近更新 更多