【问题标题】:Extract subarrays of numpy array whose values are above a threshold提取值高于阈值的numpy数组的子数组
【发布时间】:2017-09-01 16:52:57
【问题描述】:

我有一个声音信号,作为一个 numpy 数组导入,我想将它切割成多个 numpy 数组。但是,我希望这些块只包含高于阈值的元素。例如:

threshold = 3
signal = [1,2,6,7,8,1,1,2,5,6,7]

应该输出两个数组

vec1 = [6,7,8]
vec2 = [5,6,7]

好的,以上是列表,但你明白我的意思。

到目前为止,这是我尝试过的,但这只会杀死我的 RAM

def slice_raw_audio(audio_signal, threshold=5000):

    signal_slice, chunks = [], []

    for idx in range(0, audio_signal.shape[0], 1000):
        while audio_signal[idx] > threshold:
            signal_slice.append(audio_signal[idx])
         chunks.append(signal_slice)
    return chunks

【问题讨论】:

  • 如何定义块的大小?
  • 从第一个大于阈值的元素到最后一个。下一个块相同...
  • 您可以产生每个切片而不是返回所有内容,因此在迭代时并非所有内容都在内存中,如果这是您唯一的问题。此外,您应该将信号数组转换为常规列表以进行迭代,numpy 只会减慢您的速度。

标签: python arrays numpy slice


【解决方案1】:

这是一种方法 -

def split_above_threshold(signal, threshold):
    mask = np.concatenate(([False], signal > threshold, [False] ))
    idx = np.flatnonzero(mask[1:] != mask[:-1])
    return [signal[idx[i]:idx[i+1]] for i in range(0,len(idx),2)]

示例运行 -

In [48]: threshold = 3
    ...: signal = np.array([1,1,7,1,2,6,7,8,1,1,2,5,6,7,2,8,7,2])
    ...: 

In [49]: split_above_threshold(signal, threshold)
Out[49]: [array([7]), array([6, 7, 8]), array([5, 6, 7]), array([8, 7])]

运行时测试

其他方法 -

# @Psidom's soln
def arange_diff(signal, threshold):
    above_th = signal > threshold
    index, values = np.arange(signal.size)[above_th], signal[above_th]
    return np.split(values, np.where(np.diff(index) > 1)[0]+1)

# @Kasramvd's soln   
def split_diff_step(signal, threshold):   
    return np.split(signal, np.where(np.diff(signal > threshold))[0] + 1)[1::2]

时间安排 -

In [67]: signal = np.random.randint(0,9,(100000))

In [68]: threshold = 3

# @Kasramvd's soln 
In [69]: %timeit split_diff_step(signal, threshold)
10 loops, best of 3: 39.8 ms per loop

# @Psidom's soln
In [70]: %timeit arange_diff(signal, threshold)
10 loops, best of 3: 20.5 ms per loop

In [71]: %timeit split_above_threshold(signal, threshold)
100 loops, best of 3: 8.22 ms per loop

【讨论】:

  • 出了点问题,如果我将阈值设置为 2000 ,则列表的第一个元素是数组([2008],dtype=int16)。如果我看一下声音表,显然不止一个开头的元素在 2000 以上。
  • @Quubix 也许后面的那些与输入数组2008 中的2008 不按顺序排列signal
【解决方案2】:

这是一个 Numpythonic 方法:

In [115]: np.split(signal, np.where(np.diff(signal > threshold))[0] + 1)
Out[115]: [array([1, 2]), array([6, 7, 8]), array([1, 1, 2]), array([5, 6, 7])]

请注意,这将为您提供所有基于拆分逻辑的较低和较高项目(基于 diff 并继续项目)它们始终是交错的,这意味着您可以通过索引将它们简单地分开:

In [121]: signal = np.array([1,2,6,7,8,1,1,2,5,6,7])

In [122]: np.split(signal, np.where(np.diff(signal > threshold))[0] + 1)[::2]
Out[122]: [array([1, 2]), array([1, 1, 2])]

In [123]: np.split(signal, np.where(np.diff(signal > threshold))[0] + 1)[1::2]
Out[123]: [array([6, 7, 8]), array([5, 6, 7])]

您可以将列表中的第一项与threshold 进行比较,以找出上面的哪一个切片将为您提供较高的项。

一般可以使用下面的sn-p来获取上面的项:

np.split(signal, np.where(np.diff(signal > threshold))[0] + 1)[signal[0] < threshold::2]

【讨论】:

  • 本来是一样的,但你很快!
  • @ColonelBeauvel 我的运气;)。不过我应该更新答案。
  • 猜 OP 只想要高于阈值的元素?
  • @Divakar 是的,这就是我提到我要更新答案的原因。
【解决方案3】:

这是一种选择:

above_th = signal > threshold
index, values = np.arange(signal.size)[above_th], signal[above_th]
np.split(values, np.where(np.diff(index) > 1)[0]+1)
# [array([6, 7, 8]), array([5, 6, 7])]

包装在一个函数中:

def above_thresholds(signal, threshold):
    above_th = signal > threshold
    index, values = np.arange(signal.size)[above_th], signal[above_th]
    return np.split(values, np.where(np.diff(index) > 1)[0]+1)

above_thresholds(signal, threshold)
# [array([6, 7, 8]), array([5, 6, 7])]

【讨论】:

    猜你喜欢
    • 2021-02-26
    • 2017-07-10
    • 2011-04-23
    • 2018-04-21
    • 2011-12-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多