【问题标题】:Computing moving median with scipy generic_filter and numpy median_filter gives different outputs用 scipy generic_filter 和 numpy median_filter 计算移动中值会给出不同的输出
【发布时间】:2019-11-07 00:29:58
【问题描述】:

我希望实现一个快速移动的中位数,因为我必须为我的程序做很多中位数。我想使用 python 内置函数,因为它们比我能做的更优化。

我的中位数应该这样做:

  • 提取 5 个值,
  • 删除中间的一个,
  • 找出剩余 4 个值的中位数。

基本上多次调用:

numpy.median(np.array([0, 1, 2, 3, 4])[np.array([True, True, False, True, True])])
# (1. + 3.) / 2. = 2.0

我找到了两个函数:scipy generic_filter 和 scipy median_filter。我的问题是 generic_filter 给出了正确的输出,而不是 median_filter,即使它们似乎具有相同的参数。此外,generic_filter 比 median_filter 慢。所以我想知道我在调用 median_filter 时做错了什么,并将这个用于提高速度。

import numpy as np
import scipy.ndimage as sc

v = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])

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)

print(sc.median_filter(v, footprint=np.array([1, 1, 0, 1, 1]), output=np.float64, mode="mirror"))
%timeit sc.median_filter(v, footprint=np.array([1, 1, 0, 1, 1]), output=np.float64, mode="mirror")

如您所见,generic_filter 给出了正确的输出: [1.5 1.5 2. 3. 4. 5. 6. 7. 8. 8.5 8.5] 每个循环 327 µs ± 15.2 µs(7 次运行的平均值 ± 标准偏差,每次 1000 个循环)

并且 median_filter 更快,但我不明白它的输出: [2. 2. 3. 4. 5. 6. 7. 8. 9. 9. 9.] 每个循环 12.4 µs ± 217 ns(7 次运行的平均值 ± 标准偏差,每次 100000 次循环)

你知道我的电话有什么问题吗?

【问题讨论】:

    标签: python numpy scipy median


    【解决方案1】:

    唯一的区别似乎在于“关系”的处理方式:

    • sc.median 返回平局的平均值
    • sc.median_filter 似乎系统地返回了更大的值

    鉴于median_filter is implemented 的方式,对于“偶数个元素的中位数应该返回平局的平均值”的情况,有效地处理特殊/特定情况很尴尬

    我已经编写了一个可以处理这种情况的版本:

    from scipy.ndimage.filters import _rank_filter
    
    def median_filter(input, footprint, output=None, mode="reflect", cval=0.0, origin=0):
        filter_size = np.where(footprint, 1, 0).sum()
        rank = filter_size // 2
        result = _rank_filter(
            input, rank, None, footprint, output, mode, cval, origin, 'dummy')
        if filter_size % 2 == 0:
            if result is output:
                tmp = result.copy()
            else:
                tmp = result
            rank -= 1
            assert rank > 0
            result = _rank_filter(
                input, rank, None, footprint, output, mode, cval, origin, 'dummy')
            # fix up ties without creating any more garbage
            result += tmp
            result /= 2
        return result
    

    但它有点笨重,并且使用了 scipy 的内部功能(我使用的是 1.3.0),因此将来可能会中断

    在我的机器上这些基准为:

    • sc.generic_filter 每个循环耗时 578 µs ± 8.51 µs
    • sc.median_filter 每个循环耗时 27.4 µs ± 1.37 µs
    • 我的median_filter 每个循环需要 65.6 µs ± 1.29 µs

    【讨论】:

    • 非常感谢您的解释!还要感谢您的实施和可能的弃用警告,我会看看我能用它做什么!
    猜你喜欢
    • 2012-01-30
    • 1970-01-01
    • 2012-12-28
    • 2017-05-12
    • 2017-01-21
    • 1970-01-01
    相关资源
    最近更新 更多