如何制作一个连续包含 numpy 数组的另一个元素的循环以计算 运行 方差?

How to make a loop that successively includes one more element of a numpy array in order to calculate the running variance?

我将数字存储在数组中,例如 [1, 6, 12, 4...]。我想做一个计算,其中每个新迭代将使用数组的一个元素。

任何对 Python 中的 statistics/variance 感兴趣的人的详细信息:

我想计算数组中数据的 运行 方差。在 Python 中获取整个数组的方差似乎很简单。所以我将我的数组放在循环中直到元素 i 。我将随着循环的进行和数组计算方差 "grows." 如果有人知道更好的方法,我将不胜感激。

您可以使用slices:

>>>> seq = [1, 2, 3, 4]
>>>> for i in range(len(seq)):
....     print(sum(seq[:i+1]))
....
1
3
6
10

希望对您有所帮助。

根据您想要的效率,您可以采用不同的方式。

最直接的就是用切片求和到当前值:

ls = [1, 6, 12, 4]

for i in range(len(ls)):
    print(sum(ls[:i+1]))

但是您会发现,随着时间的推移,累加器模式会表现得更好。下面的代码删除了对 sum 的调用,将循环的计算复杂度降低到 O(n)。它在包含数十万个项目的大型数据集上的执行速度应该明显更快:

ls = [1, 6, 12, 4]

total = 0
for item in ls:
    total += item
    print(total)

这是一个很常见的模式,可以很方便地创建一个可重用的函数。下面的代码可以让您用其他行为替换 foo 行为:

def accumulate(fn, iterable):
    total = 0
    for i, item in iterable:
        total = fn(i, item, total)

def foo(i, item, total):
    print(f'The running total is {total}.')
    return total + 2 * item - i

accumulate(foo, [1, 6, 12, 4])

>>> The running total is 2.
>>> The running total is 13.
>>> The running total is 35.
>>> The running total is 40.

为了计算 numpy 数组的 运行ning 方差,您可以在列表理解中使用切片,如下所示:

import numpy as np
a = [1, 6, 12, 4]
running_var = [np.var(a[:i+1]) for i in range(len(a))]
print(running_var)
#[0.0, 6.25, 20.222222222222225, 16.1875]

但是随着您的列表变大,您将浪费计算。一种更有效的方法是跟踪 a 中值的 运行ning 和以及 a.[=20= 的平方和 运行ning ]

running_sum = 0.
running_sum_of_squares = 0.
running_var = []
for i,x in enumerate(a):
    running_sum += x
    running_sum_of_squares += x*x
    n = i+1.
    running_var.append((running_sum_of_squares - running_sum*running_sum/n)/n)
print(running_var)
#[0.0, 6.25, 20.222222222222225, 16.1875]

此计算针对的是总体方差,但您可以针对样本方差轻松调整它。


计时结果

为了展示第二种方法的巨大速度提升,这里是一个时间比较:

创建大型随机样本

np.random.seed(0)
N = 100000
a = np.random.randn(N)

方法一:列表理解

%%timeit
running_var = [np.var(a[:i+1]) for i in range(len(a))]
# 1 loop, best of 3: 11.1 s per loop

方法二:增量方差计算

def get_running_var(a):
    running_sum = 0.
    running_sum_of_squares = 0.
    running_var = []
    for i,x in enumerate(a):
        running_sum += x
        running_sum_of_squares += x*x
        n = i+1.
        running_var.append((running_sum_of_squares - running_sum*running_sum/n)/n)
    return running_var

%%timeit
get_running_var(a)
# 10 loops, best of 3: 60.5 ms per loop

10万大小的数组,增量计算快180多倍!


由于 MemoryError,我无法 运行 使用 N = 100000@user3483203's answer 上进行速度测试,因此我对大小为 10,000 的数组重复了测试.

结果如下:

  • 列表理解:100 次循环,最好的 3 次:每次循环 268 毫秒
  • 增量方差:100 次循环,最好的 3 次:每次循环 6.09 毫秒
  • user3483203 的方法:1 个循环,3 个中的最佳:每个循环 5.73 秒