如何通过循环逐步扩展numpy数组元素计算滚动方差?
高效计算滚动前i项方差的方法
嘿,这个问题问得很实在!你一开始想到的循环截取前i个元素计算方差的思路,虽然能实现需求,但存在一个明显的问题——重复计算太多。比如计算前3个元素的方差时,其实已经包含了前2个元素的计算结果,但切片重新计算相当于把前面的工作又做了一遍,当数组规模很大时,时间复杂度会达到O(n²),效率会很低。
更优的思路:增量式计算
方差的本质可以通过两个统计量推导出来:
总体方差公式:$\text{Var}(X) = E[X^2] - (E[X])^2$
其中$E[X]$是均值,$E[X^2]$是元素平方的均值
基于这个公式,我们只需要维护三个累计变量,就能在遍历数组时每一步只用当前新增的元素更新统计量,不需要重复计算前面的所有元素:
n:当前累计的元素个数sum_x:当前累计的元素总和sum_x2:当前累计的元素平方和
每新增一个元素x,我们只需要做这几步更新:
n += 1sum_x += xsum_x2 += x ** 2
然后用更新后的变量计算当前的均值、平方均值,最后代入方差公式即可。如果需要样本方差(统计中常用,除以n-1),只需要在总体方差的基础上做一点调整。
Python代码实现
def rolling_variance(arr, sample=False): n = 0 sum_x = 0.0 sum_x2 = 0.0 rolling_vars = [] for x in arr: n += 1 sum_x += x sum_x2 += x ** 2 mean = sum_x / n mean_x2 = sum_x2 / n # 计算总体方差 var = mean_x2 - mean ** 2 # 如果是样本方差,调整计算方式(n=1时样本方差无意义,设为0) if sample and n > 1: var = var * n / (n - 1) rolling_vars.append(var) return rolling_vars # 测试示例 test_arr = [1, 6, 12, 4] print("总体滚动方差:", rolling_variance(test_arr)) print("样本滚动方差:", rolling_variance(test_arr, sample=True))
运行结果:
总体滚动方差: [0.0, 6.25, 18.88888888888889, 15.1875] 样本滚动方差: [0.0, 12.5, 28.333333333333332, 20.25]
用Numpy实现向量化计算(适合大型数组)
如果你习惯用Numpy处理数值计算,可以用cumsum函数直接计算累计和与累计平方和,实现向量化的增量计算,效率会更高:
import numpy as np def numpy_rolling_variance(arr, sample=False): arr_np = np.array(arr, dtype=np.float64) n = np.arange(1, len(arr_np)+1) sum_x = np.cumsum(arr_np) sum_x2 = np.cumsum(arr_np ** 2) mean = sum_x / n mean_x2 = sum_x2 / n var = mean_x2 - mean ** 2 if sample: # 处理n=1的情况,避免除以0 var[1:] = var[1:] * n[1:] / (n[1:] - 1) return var # 测试 test_arr = [1, 6, 12, 4] print("Numpy总体滚动方差:", numpy_rolling_variance(test_arr)) print("Numpy样本滚动方差:", numpy_rolling_variance(test_arr, sample=True))
为什么这个方法更好?
- 时间复杂度是O(n):每个元素只被处理一次,没有重复计算,数组越大,和切片法的效率差距越明显。
- 内存效率高:只需要维护几个变量(或Numpy的几个一维数组),不需要每次生成新的切片数组。
内容的提问来源于stack exchange,提问作者Ant
相关产品推荐
相关产品推荐

