使用scipy位数_过滤器实现移动中位数

时间:2019-06-20 11:15:30

标签: python numpy scipy median

注意:问题开始变得越来越大,因此我在另一个问题中重新阐述了所有问题: 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的调用没有给出相同的输出?

0 个答案:

没有答案