如何使用Numpy.strides重实现带重置的滚动求和?
无循环实现带重置的滚动求和(NumPy)
你的需求是每window_size个元素就重置求和,从头开始累加,以下是两种无需循环的高效实现方式,性能远优于原循环方法:
方法一:分块累积和(简单直观)
这种方法通过将数组按窗口大小分块,对每块计算累积和后拼接结果,逻辑清晰且无需复杂操作:
def rolling_sum_with_reset_block(arr, window_size): arr = np.asarray(arr) # 补全数组长度至window_size的整数倍(补0不影响求和结果) pad_length = (window_size - len(arr) % window_size) % window_size padded_arr = np.pad(arr, (0, pad_length), mode="constant") # 分块并计算每块的累积和 block_cumsum = np.cumsum(padded_arr.reshape(-1, window_size), axis=1) # 展平后截取原数组长度的结果 return block_cumsum.flatten()[:len(arr)]
方法二:使用np.lib.stride_tricks.as_strided
如果一定要用stride_tricks,可以通过创建数组视图来实现分块(本质和分块法逻辑一致,但利用了视图避免数据复制):
def rolling_sum_with_reset_strided(arr, window_size): arr = np.asarray(arr) n = len(arr) n_full_blocks = n // window_size remainder = n % window_size # 处理完整窗口块:用strided创建视图 full_block_view = np.lib.stride_tricks.as_strided( arr[:n_full_blocks * window_size], shape=(n_full_blocks, window_size), strides=(arr.strides[0] * window_size, arr.strides[0]) ) full_cumsum = np.cumsum(full_block_view, axis=1).flatten() # 处理剩余不足一个窗口的元素 if remainder > 0: rem_cumsum = np.cumsum(arr[n_full_blocks * window_size:]) return np.concatenate([full_cumsum, rem_cumsum]) return full_cumsum
验证与性能
两种方法的结果和原循环函数完全一致:
original_result = rolling_sum_with_reset(apple_volume, 3) block_result = rolling_sum_with_reset_block(apple_volume, 3) strided_result = rolling_sum_with_reset_strided(apple_volume, 3) print(np.array_equal(original_result, block_result)) # 输出 True print(np.array_equal(original_result, strided_result)) # 输出 True
在大数据量场景下,向量运算的方法比循环快数十倍,尤其适合处理长时序数据。
内容的提问来源于stack exchange,提问作者Merlin
相关产品推荐
相关产品推荐

