python - 用 scipy generic_filter 和 numpy median_filter 计算移动中值会给出不同的输出
问题描述
我希望实现一个快速移动的中位数,因为我必须为我的程序做很多中位数。我想使用 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 次循环)
你知道我的电话有什么问题吗?
解决方案
唯一的区别似乎是由于“关系”的处理方式:
sc.median
返回平局的平均值sc.median_filter
似乎系统地返回更大的值
考虑到median_filter
实现的方式,对于“偶数个元素的中位数应该返回关系的平均值”的情况,处理特殊/特定是很尴尬的
我已经破解了一个处理这种情况的版本:
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 µssc.median_filter
每个循环需要 27.4 µs ± 1.37 µs- 我
median_filter
的每个循环需要 65.6 µs ± 1.29 µs
推荐阅读
- python - 解决简单的python列表迭代
- pyspark - 获取 pyspark 列表中的行值
- html - 导航选项卡不使用溢出-x滚动:滚动
- serial-port - 树莓派和nayax设备支付网关通信使用树莓派3的usb端口
- node.js - 如何在不同端口上构建具有多个功能区域的 React App?
- dll - nsis - 加载插件 dll
- angular - 错误 - 此命令只能在 CLI 项目内运行
- android - Android Wear:无法通过 wifi 或蓝牙连接手表
- android - Android studio 无法将 apk 安装到 Xiaomi Note5A (Redmi) 中(安装失败并显示 INSTALL_FAILED_USER_RESTRICTED 消息:)
- objective-c - Swift 4:将 Objective-c 转换为 Swift 时,非标称类型“T”不支持显式初始化