我写了一段代码来查找时间序列中的峰,我也希望它能绘制局部基线。目前,我正在使用由两个余弦曲线构建的测试时间序列。
代码如下,其中p_times是峰中心的时间:
step = 0.1
time = np.arange(0, 10.1, step)
#Does stuff to find peaks
p_times = [0.9, 1., 1.1, 1.9, 2., 2.1, 2.9, 3., 3.1, 3.9, 4., 4.1, 4.9, 5., 5.1, 5.9, 6., 6.1, 6.9, 7., 7.1, 7.9, 8., 8.1, 8.9, 9., 9.1]
idx = np.array([np.where(time == x)[0][0] for x in p_times])
最后一条指令应该给出一个数组,其中包含与峰值相对应的时间元素的索引,但是我得到了:
IndexError: index 0 is out of bounds for axis 0 with size 0
使情况变得奇怪的是,将余弦曲线参数更改为看起来有些“幸运”的值,峰的位置也发生了变化,并且代码有效:
p_times = [0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 8.5, 9., 9.5]
# result: idx = [ 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95]
更新:再次使用“不幸的”时间序列,我得到了以下高峰时间数组:
p_times = [0.3, 1.8, 1.9, 2., 2.1, 2.2, 3.7, 3.8, 3.9, 4., 4.1, 4.2, 4.3, 5.8, 5.9, 6., 6.1, 6.2, 7.7, 7.8, 7.9, 8., 8.1, 8.2, 8.3]
说明:
idx_c = np.array([np.where(np.isclose(time, x))[0][0] for x in p_times])
再次失败:
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-1-4c7f86bac90c> in <module>()
53 #Baseline extremes (x,y), left and right
54 #idx_c = np.array([np.where(time == x)[0][0] for x in O[:,0]]) #Cannot manage to vectorize this
---> 55 idx_c = np.array([np.where(np.isclose(time, x))[0][0] for x in p_times])
56 print("idx_c = ", idx_c)
57 idx_l = np.array(idx_c - k) #Left extreme is at index of center (peak) minus k positions.
<ipython-input-1-4c7f86bac90c> in <listcomp>(.0)
53 #Baseline extremes (x,y), left and right
54 #idx_c = np.array([np.where(time == x)[0][0] for x in O[:,0]]) #Cannot manage to vectorize this
---> 55 idx_c = np.array([np.where(np.isclose(time, x))[0][0] for x in p_times])
56 print("idx_c = ", idx_c)
57 idx_l = np.array(idx_c - k) #Left extreme is at index of center (peak) minus k positions.
IndexError: index 0 is out of bounds for axis 0 with size 0
此行为的原因是什么?
答案 0 :(得分:5)
您的方法的主要问题是要精确比较浮点值。由于四舍五入的错误,这几乎总是一个很糟糕的主意,在这个臭名昭著的例子中得到了证明:
>>> 0.1 + 0.2 == 0.3
False
请注意,numpy双打和本机python双打在本质上是相似的(无论哪种情况,我都不确定大小取决于体系结构的依赖性,但是您可能会明白我的意思)。
因此,首先,您应始终使用np.isclose
/ np.allclose
来比较浮点数是否相等。其次,这就是我要发布完整答案的原因:您不必使用列表理解,您可以在对isclose
的单个numpy广播呼叫中执行所需的操作:
>>> idx, data_idx = np.isclose(time[:,None], p_times).nonzero()
>>> idx
array([ 9, 10, 11, 19, 20, 21, 29, 30, 31, 39, 40, 41, 49, 50, 51, 59, 60,
61, 69, 70, 71, 79, 80, 81, 89, 90, 91])
这里发生的是,通过插入尾随单例维,将time
数组转换为2d列数组,并且通过将每个time
点与每个{{1 }}点。对p_times
的最终调用返回nonzero()
值的索引:第一个输出True
包含您要查找的索引。
此方法也更安全,因为如果峰没有匹配时间,它将不会引发异常。相反,您拥有的idx
值要少于idx
点。在这种情况下,您可以使用p_times
来找到实际发现的峰的索引:
data_idx