如何加速Numpy数组的滑动窗口子数组提取操作?
如何高效提取Numpy数组的滑动窗口子数组?
你的问题核心是循环中反复调用np.append导致的性能瓶颈——每次append都会创建新数组并复制已有数据,随着结果数组越来越大,这个操作的耗时会指数级上升。分半处理虽然能减半循环次数,但本质还是没解决重复复制的问题,所以提升有限。
这里给你两个高效的解决方案,完全不需要循环,利用Numpy的底层机制直接生成所有滑动窗口:
1. 优先推荐:使用np.lib.stride_tricks.sliding_window_view(Numpy 1.20+)
这是Numpy官方在1.20版本新增的安全滑动窗口工具,它不会复制原始数据,只是创建一个新的数组视图,速度和内存效率都拉满。
示例代码:
import numpy as np a = np.array([55, 12, 12, ...]) # 你的大型输入数组 WINDOW = 300 window_length = WINDOW + 1 # 对应你原代码里的i:i+WINDOW+1 # 一步生成所有滑动窗口,形状为 (len(a)-WINDOW, WINDOW+1) sliding_windows = np.lib.stride_tricks.sliding_window_view(a, window_shape=window_length)
生成的sliding_windows和你循环生成的new_a结构完全一致,但效率提升几个数量级,处理大型数组时几乎瞬间完成。
2. 低版本Numpy兼容方案:np.lib.stride_tricks.as_strided
如果你用的是低于1.20的Numpy版本,可以手动用as_strided实现,但要注意计算字节步长,避免内存越界:
import numpy as np a = np.array([55, 12, 12, ...]) WINDOW = 300 window_length = WINDOW + 1 num_windows = len(a) - window_length + 1 # 计算原始数组的字节步长,这里假设数组是int64类型(每个元素8字节) # 如果是其他类型,比如float32,要替换成a.itemsize strides = (a.strides[0], a.strides[0]) sliding_windows = np.lib.stride_tricks.as_strided( a, shape=(num_windows, window_length), strides=strides )
⚠️ 注意:as_strided直接操作内存,若计算错误可能导致读取非法内存,所以仅在无法升级Numpy时使用,优先选第一种方案。
为什么你的原有方法慢?
np.append本质是每次调用都执行np.concatenate,会把原有数据复制到新数组中。循环1000次就会复制1000次数据,数据量越大,每次复制的耗时越高。- 分半处理只是减少了循环次数,但每次循环里的
append仍然在复制数据,所以只能减半耗时,无法从根本上解决问题。
内容的提问来源于stack exchange,提问作者Incompleteness
相关产品推荐
相关产品推荐

