如何用Numpy高效实现滑动中位数?替代列表推导式方案
用Numpy实现高效滑动中位数
当然可以用纯Numpy函数实现滑动中位数,而且效率远高于列表推导式循环调用np.median的方式。核心思路是利用Numpy的滑动窗口视图和向量化排序避免Python循环开销,以下是两种可行的实现方案:
方案1:使用内置滑动窗口视图(推荐,Numpy 1.20+)
利用np.lib.stride_tricks.sliding_window_view生成滑动窗口的内存视图(无需复制原数组),再对所有窗口批量排序后提取中位数:
import numpy as np def sliding_median(arr, window): # 生成滑动窗口视图,共享原数组内存 windows = np.lib.stride_tricks.sliding_window_view(arr, window_shape=window) # 对每个窗口沿轴1排序(向量化操作,效率远高于循环排序) sorted_windows = np.sort(windows, axis=1) # 计算中位数对应的索引 mid_idx = window // 2 # 区分奇偶窗口的中位数计算逻辑 if window % 2 == 1: return sorted_windows[:, mid_idx] else: return (sorted_windows[:, mid_idx-1] + sorted_windows[:, mid_idx]) / 2.0
方案2:手动构造滑动窗口(兼容旧版Numpy)
如果你的Numpy版本低于1.20,可以用np.lib.stride_tricks.as_strided手动构造滑动窗口,原理和方案1一致:
import numpy as np def sliding_median_old(arr, window): arr_len = len(arr) num_windows = arr_len - window + 1 # 计算内存步长,确保窗口连续且共享原数组内存 elem_size = arr.itemsize windows = np.lib.stride_tricks.as_strided( arr, shape=(num_windows, window), strides=(elem_size, elem_size) ) sorted_windows = np.sort(windows, axis=1) mid_idx = window // 2 if window % 2 == 1: return sorted_windows[:, mid_idx] else: return (sorted_windows[:, mid_idx-1] + sorted_windows[:, mid_idx]) / 2.0
效率对比说明
原列表推导式方案每次循环都要单独调用np.median,而np.median内部会重复执行排序操作;上述方案通过批量排序所有滑动窗口,彻底避免了Python循环的开销,同时滑动窗口视图无需复制原数组内存,内存效率也更高。
测试示例
# 测试代码 arr = np.array([1,3,5,7,9,2,4,6,8]) window = 3 print(sliding_median(arr, window)) # 输出: [3. 5. 7. 7. 5. 4. 6.]
内容的提问来源于stack exchange,提问作者Smer5
相关产品推荐
相关产品推荐

