在 numpy 中寻找最小跳跃过零点
Finding minimal jump zero crossings in numpy
对于数据分析任务,我想在一个 numpy 数组中找到零交叉点,它来自一个卷积,首先是一个类似 sobel 的内核,然后是一个墨西哥帽内核。零交叉允许我检测数据中的边缘。
不幸的是,数据有些嘈杂,我只想找到具有最小跳跃大小的零交叉,20
在以下示例中:
import numpy as np
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
应该导致
>>>array([1, 3, 7])
或
>>>array([3, 7])
其中 3
是 -1
的索引,就在第一次跳跃的中间之前, 7
是 -10
的索引
我尝试修改以下代码(来源:Efficiently detect sign-changes in python)
zero_crossings = np.where(np.diff(np.sign(np.trunc(arr/10))))[0]
这正确地忽略了小跳跃,但将过零置于 [1,5,7]
执行此操作的有效方法是什么?
最小跳跃的定义并不严格,但结果应该与我的问题一致。
编辑:澄清
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
arr_floored = np.trunc(arr/10)
>>>>np.array([10, 10, 0, 0, 0, 0, -10, -10, 10])
sgn = np.sign(arr_floored)
>>>>array([ 1, 1, 0, 0, 0, 0, -1, -1, 1])
dsgn = np.diff(sgn)
>>>>array([ 0, -1, 0, 0, 0, -1, 0, 2])
np.where(dsgn)
>>>>(array([1, 5, 7], dtype=int64),)
更多边缘情况:
arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
应该导致
>>> np.array([10])
刚刚还注意到:这个问题可能不适定(在数学意义上)。我会在今天晚些时候澄清。
基本案例
我猜你想要
import numpy as np
x = np.array([10, -50, -30, 50, 10, 3, -200, -12, 123])
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]
读作:指数,其中((x 的绝对差值)大于或等于 20)和(符号翻转)
哪个returns
array([0, 2, 5, 7])
周期信号
通常的 numpy 函数不包括这种情况。我建议通过 pad 函数在最后简单地添加第一个元素:
import numpy as np
x = np.array([10, 5, 0, -5, -10])
x = np.pad(x, (0, 1), 'wrap')
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]
这是一个解决方案,它给出了涉及噪声阈值的交叉点的中点,以过滤跨多个数据点应用的零附近的潜在多重波动。它为您提供的两个示例给出了正确答案。
但是,我做了几个假设:
- 您没有准确定义要考虑的数据点范围以确定交叉点的中点,但我使用您的示例代码作为基础 - 它正在检测交叉点
ABS(start | end) >= 10
因此我使用了满足此条件的 最小值 范围。
注意:这不会检测到从 +15 到 -6 的转换。
编辑:实际上它并不总是最小范围,但代码应该足以让您开始并根据需要进行调整。
- 我假设也可以使用 pandas(跟踪感兴趣的数据点的索引)。如果必要的话,你可以避免 pandas。
import numpy as np
import pandas as pd
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
sgn = pd.Series(np.sign(np.trunc(arr/10)))
trailingEdge = sgn[sgn!=0].diff()
edgeIndex = np.array(trailingEdge[trailingEdge!=0].index)
edgeIndex[:-1] + np.diff(edgeIndex) / 2
给出:
array([3., 7.])
和
arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
给出:
array([10.])
对于数据分析任务,我想在一个 numpy 数组中找到零交叉点,它来自一个卷积,首先是一个类似 sobel 的内核,然后是一个墨西哥帽内核。零交叉允许我检测数据中的边缘。
不幸的是,数据有些嘈杂,我只想找到具有最小跳跃大小的零交叉,20
在以下示例中:
import numpy as np
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
应该导致
>>>array([1, 3, 7])
或
>>>array([3, 7])
其中 3
是 -1
的索引,就在第一次跳跃的中间之前, 7
是 -10
我尝试修改以下代码(来源:Efficiently detect sign-changes in python)
zero_crossings = np.where(np.diff(np.sign(np.trunc(arr/10))))[0]
这正确地忽略了小跳跃,但将过零置于 [1,5,7]
执行此操作的有效方法是什么?
最小跳跃的定义并不严格,但结果应该与我的问题一致。
编辑:澄清
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
arr_floored = np.trunc(arr/10)
>>>>np.array([10, 10, 0, 0, 0, 0, -10, -10, 10])
sgn = np.sign(arr_floored)
>>>>array([ 1, 1, 0, 0, 0, 0, -1, -1, 1])
dsgn = np.diff(sgn)
>>>>array([ 0, -1, 0, 0, 0, -1, 0, 2])
np.where(dsgn)
>>>>(array([1, 5, 7], dtype=int64),)
更多边缘情况:
arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
应该导致
>>> np.array([10])
刚刚还注意到:这个问题可能不适定(在数学意义上)。我会在今天晚些时候澄清。
基本案例
我猜你想要
import numpy as np
x = np.array([10, -50, -30, 50, 10, 3, -200, -12, 123])
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]
读作:指数,其中((x 的绝对差值)大于或等于 20)和(符号翻转)
哪个returns
array([0, 2, 5, 7])
周期信号
通常的 numpy 函数不包括这种情况。我建议通过 pad 函数在最后简单地添加第一个元素:
import numpy as np
x = np.array([10, 5, 0, -5, -10])
x = np.pad(x, (0, 1), 'wrap')
indices = np.where(np.logical_and(np.abs(np.diff(x)) >= 20, np.diff(np.sign(x)) != 0))[0]
这是一个解决方案,它给出了涉及噪声阈值的交叉点的中点,以过滤跨多个数据点应用的零附近的潜在多重波动。它为您提供的两个示例给出了正确答案。 但是,我做了几个假设:
- 您没有准确定义要考虑的数据点范围以确定交叉点的中点,但我使用您的示例代码作为基础 - 它正在检测交叉点
ABS(start | end) >= 10
因此我使用了满足此条件的 最小值 范围。
注意:这不会检测到从 +15 到 -6 的转换。
编辑:实际上它并不总是最小范围,但代码应该足以让您开始并根据需要进行调整。 - 我假设也可以使用 pandas(跟踪感兴趣的数据点的索引)。如果必要的话,你可以避免 pandas。
import numpy as np
import pandas as pd
arr = np.array([12, 15, 9, 8, -1, 1, -12, -10, 10])
sgn = pd.Series(np.sign(np.trunc(arr/10)))
trailingEdge = sgn[sgn!=0].diff()
edgeIndex = np.array(trailingEdge[trailingEdge!=0].index)
edgeIndex[:-1] + np.diff(edgeIndex) / 2
给出:
array([3., 7.])
和
arr = [10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10]
给出:
array([10.])