是否有一种快速(准确)的方法来计算数据集的样本方差,直到第 n 个元素?

Is there a fast (and accurate) way to calculate the sample variance of a data-set till the n-th element?

我需要计算数据集的样本方差直到第 n 个元素,例如

x = np.random.randint(1, 7, 10)
--> [5 2 2 5 3 5 2 5 4 2]

快速简便的方法是使用 np.var(x) 或 Welfords 算法的实现,但它们只计算整个数据集的方差。 对于我的应用程序,我需要一个数组中的方差元素,以便在第 n 个元素中它将是与数据集中第一个第 n 个数据点的方差。

例如:

x_var[2]
--> variance of [5 2 2]
--> 1.7320508
x_var[9]
--> variance of [5 2 2 5 3 5 2 5 4 2]
--> 2.0555556

我的解决方案是将数组分割成 n 个数组,这样我就可以在每个数组上使用 np.var 来获得 运行 方差。这有效,但速度非常慢。

for i in range(0,n):                                                
    x_var[i] = np.var(x[:i]) 

我已经快速实现了 运行 均值,所以我有一个数组,其中的均值一直到第 n 个条目中的第 n 个元素,如果有帮助的话。

如果不将数组分割成 n 块,您将如何高效准确地解决这个问题?

一个简单的方法是使用 pandasexpanding and var(ddof=0):

import numpy as np
import pandas as pd

x = np.array([5, 2, 2, 5, 3, 5, 2, 5, 4, 2])

pd.Series(x).expanding().var(ddof=0).to_numpy()

输出:

array([0.        , 2.25      , 2.        , 2.25      , 1.84      ,
       1.88888889, 1.95918367, 1.984375  , 1.77777778, 1.85      ])

我实际上也会采用 pandas 方法。但是,一种使用不需要切片的纯 numpy 的可能解决方案是

def running_mean(x:np.array) -> np.array:
    return np.cumsum(x) / np.arange(1,len(x) + 1)

def running_var(x:np.array) -> np.array:
    means = running_mean(x)
    return ((np.tril(x) - np.triu(means).T) ** 2).sum(axis=1) / np.arange(1,len(x) + 1)

所以基本上使用 运行 均值函数,但是将其转换为三角矩阵并从那里进行数学运算。由于创建了那些大小为 N x N 的三角矩阵,对于大 x,这可能会变得很慢。