如何使用Numpy计算向量滚动窗口的相关系数
如何使用Numpy计算向量滚动窗口的相关系数
嘿,我完全理解你想要摆脱循环、用更高效的Numpy向量化操作来计算滚动窗口相关系数的需求——循环不仅写起来麻烦,在数据量较大时效率也会差很多。咱们可以通过拆解相关系数的计算公式,结合Numpy的滑动窗口工具来实现无循环的解决方案!
首先,先回顾一下相关系数的本质:两个变量的协方差除以它们各自标准差的乘积。因为你是和固定的数组[0,1,2,3,4]计算相关系数,这个固定数组的均值和标准差是可以提前一次性算好的,不用重复计算,这能省不少功夫。
具体实现步骤
提前计算固定数组的统计量
我们要对比的固定数组是y = np.arange(5),先算出它的均值和总体标准差(和np.corrcoef保持一致,用ddof=0):import numpy as np data = np.array([10,5,8,9,15,22,26,11,15,16,18,7,4,8,-2,-3,-4,-6,-2,0,10,0,5,8]) length = 5 y = np.arange(length) y_mean = y.mean() y_std = y.std(ddof=0) # 对应np.corrcoef的总体标准差计算方式生成所有滚动窗口的数据集
使用Numpy的np.lib.stride_tricks.sliding_window_view(Numpy 1.20+支持)可以快速生成所有长度为5的滚动窗口,然后我们截取和你循环逻辑对应的窗口(前19个,对应原循环中i从5到23的情况):# 生成所有滚动窗口,形状为(20,5),截取前19个匹配原循环逻辑 window_data = np.lib.stride_tricks.sliding_window_view(data, length)[:-1]如果你的Numpy版本较低,没有
sliding_window_view,可以用手动 stride 实现的滚动窗口函数替代:def rolling_window(arr, window_size): shape = arr.shape[:-1] + (arr.shape[-1] - window_size + 1, window_size) strides = arr.strides + (arr.strides[-1],) return np.lib.stride_tricks.as_strided(arr, shape=shape, strides=strides) window_data = rolling_window(data, length)[:-1]批量计算每个窗口的统计量和相关系数
用向量化操作批量计算每个窗口的均值、标准差,以及和y的协方差,最后算出相关系数:# 每个窗口的均值和总体标准差 window_means = window_data.mean(axis=1) window_stds = window_data.std(axis=1, ddof=0) # 计算每个窗口与y的协方差 cov = np.mean((window_data - window_means[:, np.newaxis]) * (y - y_mean), axis=1) # 计算相关系数 r = cov / (window_stds * y_std)构造最终结果数组
和你的原代码一样,前5个元素填充0,后面填充计算出的相关系数:x = np.zeros_like(data, dtype='float32') x[length:] = r
验证结果
运行上面的代码后,你得到的x数组和原循环代码输出的结果完全一致:
[ 0. 0. 0. 0. 0. 0.607 0.959 0.98 0.328 -0.287 -0.61 -0.314 -0.18 -0.8 -0.782 -0.847 -0.811 -0.825 -0.869 -0.283 0.566 0.863 0.643 0.454]
这种方法完全利用了Numpy的向量化优势,比循环快得多,尤其是当你的数据量很大的时候效果会更明显!
备注:内容来源于stack exchange,提问作者tibibou




