繁体   English   中英

在Python中有效地查找大于阈值的第一个样本(和MATLAB比较)

[英]Finding first samples greater than a threshold value efficiently in Python (and MATLAB comparison)

我想找到signal变得大于threshold的第一个样本,而不是找到列表或数组中大于特定threshold所有样本/数据点。 信号可能会多次超过阈值。 例如,如果我有一个示例信号:

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

然后, threshold = 2

signal = numpy.array(signal)
is_bigger_than_threshold = signal > threshold

会给我signal中所有大于threshold 但是,每当信号变得大于阈值时,我想只得到第一个样本。 因此,我将浏览整个列表并进行布尔比较

first_bigger_than_threshold = list()
first_bigger_than_threshold.append(False)
for i in xrange(1, len(is_bigger_than_threshold)):
    if(is_bigger_than_threshold[i] == False):
        val = False
    elif(is_bigger_than_threshold[i]):
        if(is_bigger_than_threshold[i - 1] == False):
            val = True
        elif(is_bigger_than_threshold[i - 1] == True):
            val = False
    first_bigger_than_threshold.append(val)

这给了我正在寻找的结果,即

[False, False, True, False, False, False, False, False, False, True, False, False, False,   
False, False, False, True, False, False, False, False, False]

在MATLAB中,我会做同样的事情

for i = 2 : numel(is_bigger_than_threshold)
    if(is_bigger_than_threshold(i) == 0)
        val = 0;
    elseif(is_bigger_than_threshold(i))
        if(is_bigger_than_threshold(i - 1) == 0)
            val = 1;
        elseif(is_bigger_than_threshold(i - 1) == 1)
            val = 0;
        end
    end
    first_bigger_than_threshold(i) = val;
end % for

是否有更有效(更快)的方式来执行此计算?

如果我用Python生成数据,例如

signal = [round(random.random() * 10) for i in xrange(0, 1000000)]

并计算这些值需要4.45秒。 如果我在MATLAB中生成数据

signal = round(rand(1, 1000000) * 10);

并执行该程序只需0.92秒。

为什么MATLAB比执行此任务的速度快5倍?

提前感谢您的意见!

其他答案给你第一个Trues的位置,如果你想要一个标记第一个True的bool数组,你可以更快地做到:

import numpy as np

signal = np.random.rand(1000000)
th = signal > 0.5
th[1:][th[:-1] & th[1:]] = False

这篇文章解释了为什么你的代码比Matlab慢。

试试这个代码

import numpy as np

threshold = 2
signal = np.array([1, 2, 3, 4, 4, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 1, 4, 8, 7, 6, 5, 0])

indices_bigger_than_threshold = np.where(signal > threshold)[0] # get item
print indices_bigger_than_threshold
# [ 2  3  4  5  9 16 17 18 19 20]
non_consecutive = np.where(np.diff(indices_bigger_than_threshold) != 1)[0]+1 # +1 for selecting the next
print non_consecutive
# [4 5]
first_bigger_than_threshold1 = np.zeros_like(signal, dtype=np.bool)
first_bigger_than_threshold1[indices_bigger_than_threshold[0]] = True # retain the first
first_bigger_than_threshold1[indices_bigger_than_threshold[non_consecutive]] = True

np.where返回与条件匹配的索引。

策略是使指数高于threshold并删除连续。

顺便说一句,欢迎来到Python / Numpy世界。

基于这样一种观点,即加快速度的最佳方法是选择最佳算法,您可以使用简单的边缘检测器巧妙地做到这一点:

import numpy

signal = numpy.array([1, 2, 3, 4, 4, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 1, 4, 8, 7, 6, 5, 0])

thresholded_data = signal > threshold
threshold_edges = numpy.convolve([1, -1], thresholded_data, mode='same')

thresholded_edge_indices = numpy.where(threshold_edges==1)[0]

print(thresholded_edge_indices)

打印[2 9 16] ,对应于大于阈值的序列中的第一个条目的索引。 这将使Matlab和Python(使用Numpy)的速度更快 - 在我的机器上大约12ms来完成4.5s的操作。

编辑:正如@eickenberg所指出的,卷积可以用numpy.diff(thresholded_data)替换,这在概念上稍微简单一些,但在这种情况下,索引会超出1,所以记得把它们添加回去,还可以使用thresholded_data.astype(int)thresholded_data转换为int数组。 两种方法之间没有明显的速度差异。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM