嗨蟒蛇爱好者!
我目前正在研究用于研究目的的信号过滤,并决定使用SciPy。没什么特别的,只是日常工作的自动化。
所以,这是代码
from scipy.signal import medfilt
print(medfilt([2,6,5,4,0,3,5,7,9,2,0,1], 5))
但问题是返回的序列计算错误
SciPy: [ 2. 4. 4. 4. 4. 4. 5. 5. 5. 2. 1. 0.]
Me : [ 5. 4.5 4. 4. 4. 4. 5. 5. 5. 2. 1.5 1.]
似乎是,包的开发人员搞砸了一个细节。当光圈(SciPy中的内核)大于要分析的窗口时,还有另一种过滤规则。
例如,kernel=5
过滤后的[2, 6, 5]
子序列的中位数为5而不是2,因为SciPy计算的不是吗?同样,如果kernel=5
对于子序列[2,6,5,4]
中位数为5和4,我们需要在它们之间取平均值,因此,中位数为4.5。
有人可以解释一下我在这种情况下得到了正确的结果吗?
答案 0 :(得分:13)
我相信你和SciPy都有正确的结果。区别在于边界发生的事情,但我相信你和SciPy都做出了有效的选择。
问题是当您的滑动窗口位于边缘时会发生什么,并且没有用于填充滑动窗口的有效数据。
您选择取滑动窗口有效部分的中位数,这是有道理的,但可能会增加一些偏差,因为与其他所有点相比,您的边缘点过多。
SciPy选择通过填充零来扩展任一边缘的信号。因此,在边界上,SciPy实质上是在计算
>>> np.median([0, 0, 2, 6, 5])
2.0
>>> np.median([0, 2, 6, 5, 4])
4.0
>>> np.median([9, 2, 0, 1, 0])
1.0
>>> np.median([2, 0, 1, 0, 0])
0.0
SciPy之所以这样做几乎肯定与速度有关:它针对多次做同样的事情进行了优化,并且对于一大堆5元素阵列优化median
要比它更容易是针对一大堆5元素阵列以及两个4元素阵列和两个3元素阵列进行优化。肯定有一个论点是它不应该用零填充,而是用边界值填充,但应该注意的是没有边界策略是完美的;处理边界问题的理想方法取决于你的特定信号。
如果你看到Wikipedia's description of median filters,它们会通过用边缘的值填充它来扩展任一边缘的信号,这似乎也是合理的。他们还注意到处理边界问题的其他三种方式:
最后,您真的需要尝试不同的选项,看看什么最适合您的信号。这种滤波的核心假设是你的信号将非常大,并且边界问题永远不应该那么重要(因为边界上不存在大部分信号)。如果SciPy允许你选择它应该在边界做什么,那将是很好的!