注意:问题开始变得越来越大,因此我在另一个问题中重新阐述了所有问题: Computing moving median with scipy generic_filter and numpy median_filter gives different outputs
我希望在Python中实现一维矢量的移动中值。基本上我想做的是连续调用大小为5的numpy.median,但是我还需要一个掩码,因为每次调用我都必须去除居中元素,然后应用中位数:
import numpy as np
v = np.array([0, 1, 2, 3, 4]) # vector of size 5
mask = np.array([True, True, False, True, True]) # mask that gets rid of the centered element
print(np.median(v[mask])) #(1 + 3) / 2 = 2.0
这是下面链接的图像上显示的内容。我不能在帖子中加入它(可能太大了?),对此我表示歉意。
https://www.noelshack.com/2019-25-4-1561022011-median1.png
问题是在如此小的数组上成功调用numpy的速度很慢。我知道有一个参数轴,我可以将向量重新排序为矩阵,以便每行包含5个元素,并且我可以在一次调用中应用中值。但是我的问题是创建这个新矩阵,我宁愿使用原始向量并节省一些时间。我还宁愿称呼现有功能,因为它们将比我能做的要优化得多。
我注意到scipy中有此功能:median_filter。但是我不明白它的输出。在下面链接的图像上,我尝试解释我的理解。但是,正如您在图像底部所看到的,我期望的值与函数执行的功能之间存在差异。
https://www.noelshack.com/2019-25-4-1561023099-median2.png
我认为我误解了参数足迹的使用。这就是我调用该函数以获取橙色矢量中显示的结果的方式。但是,有了这些参数,我期望得到的结果显示在蓝色矢量中。
import numpy as np
from scipy import ndimage, misc
v = np.array([0., 1., 2., 3, 4., 5., 6., 7., 8., 9., 10.])
print(ndimage.median_filter(v, footprint=np.array([1, 1, 0, 1, 1]),
output=np.float64, mode="mirror", origin = 0))
#gives : [2. 2. 3. 4. 5. 6. 7. 8. 9. 9. 9.]
#but I expect : [1.5 1.5 2. 3. 4. 5. 6. 7. 8. 8.5 8.5]
您知道我的电话怎么了吗?还是使用Python内置函数如何获得中位数?预先谢谢你。
更新________________________________________________________更新
好吧,一位同事向我展示了此功能:scipy generic_filter。它确实可以实现我想要的功能,但是没有我想要的那么快。在我的程序中,我必须做很多中位数,并且希望此步骤花费最少的时间。在下面,您将看到通过在输入数据上创建一个子矩阵,代码的运行速度比generic_filter快。有没有办法避免创建子矩阵? Python中有没有一种方法可以在输入数据上创建视图矩阵,这样我就可以立即运行numpy中位数,而无需花费创建新矩阵的成本?再次感谢您的帮助。
# Note : How I deal with borders is not important for the question.
# With my method, I truncate the filter.
# generic_filter applies a mirror on the input data and uses the same filter.
import numpy as np
import scipy.ndimage as sc
v = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
def myMovingMedian5(IN) :
# 5 masks, 4 for borders, 1 for all other values.
mask0 = np.array([False, True, True])
mask1 = np.array([True, False, True, True])
mask2 = np.array([True, True, False, True, True])
mask3 = np.array([True, True, False, True])
mask4 = np.array([True, True, False])
nR = IN.shape[0]
# Generate a sub matrix to compute most of the medians (except on borders).
# Can I avoid this step and use IN directly ?
# Or is it possible to make a matrix of views of IN and avoid the creation of new data ?
TMP = np.zeros((nR - 4, 4))
indTMP = 0
for i in range(2, nR - 2) :
TMP[indTMP, 0:4] = (IN[i - 2:i + 3])[mask2]
indTMP = indTMP + 1
#TMP :
# [[ 0. 1. 3. 4.]
# [ 1. 2. 4. 5.]
# [ 2. 3. 5. 6.]
# [ 3. 4. 6. 7.]
# [ 4. 5. 7. 8.]
# [ 5. 6. 8. 9.]
# [ 6. 7. 9. 10.]]
# Allocate OUT matrix with 4 more elements for the borders
OUT = np.zeros(nR)
# Replace its center part by applying the median on each line of TMP
OUT[2:nR - 2] = np.median(TMP, axis = 1)
# Add remaining 4 medians on borders
OUT[0] = np.median((IN[0:3])[mask0])
OUT[1] = np.median((IN[0:4])[mask1])
beforeLast = nR - 2
OUT[beforeLast] = np.median((IN[beforeLast - 2:beforeLast + 2])[mask3])
OUT[nR - 1] = np.median((IN[nR - 3:nR])[mask4])
return OUT
print(myMovingMedian5(v))
%timeit myMovingMedian5(v)
print(sc.generic_filter(v, sc.median, footprint=np.array([1, 1, 0, 1, 1]), mode = "mirror", output=np.float64))
%timeit sc.generic_filter(v, sc.median, footprint=np.array([1, 1, 0, 1, 1]), mode = "mirror", output=np.float64)
张照片: myMovingMedian5:
[1.5 2. 2. 3. 3. 5. 5. 6. 7. 8. 8. 8.5]
每个循环121 µs±2.33 µs(平均±标准偏差,共运行7次,每个10000个循环)
scipygeneric_filter:
[1.5 1.5 2. 3. 4. 5. 6. 7. 7. 8. 8.5 8.5]
每个循环310 µs±1.5 µs(平均±标准偏差,共运行7次,每个循环1000次)
最终更新_____________________________________________最终更新
我已经检查了scipy位数_过滤器的时间,即使它没有给出正确的答案,也绝对更快:
%timeit sc.median_filter(v, footprint=np.array([1, 1, 0, 1, 1]), output=np.float64, mode="mirror")
# [2. 2. 3. 4. 5. 6. 7. 8. 9. 9. 9.]
# 12.3 µs ± 62.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
但是为什么我对general_filter和mid_filter的调用没有给出相同的输出?