快速计算数组中前n个数的均值和方差

一、问题背景

\quad给你一个数组x=[1,2,3,6]x=[1,2,3,6],如何快速计算其前缀数组x[0n]x[0\cdots n]的均值和方差,即需要返回均值数组m=[1,1.5,2,3]m=[1,1.5,2,3]m[2]=2m[2]=2表示数组x[02]=[1,2,3]x[0 \cdots 2]=[1,2,3]的均值为2;同时返回方差数组S=[0,0.25,23,3.5]]S=[0, 0.25, \frac{2}{3}, 3.5]]S[2]=2/3S[2]=2/3表示数组x[02]=[1,2,3]x[0 \cdots 2]=[1,2,3]的方差为23\frac{2}{3}
\quad对于这个问题,我们很容易找到O(n2)O(n^2)级别的算法暴力计算,那有没有O(n)O(n)级别的算法呢?
\quad我们尝试思考这样一个问题,假设我求解出了数组前n1n-1项的均值和方差,能否求出一个递推式子直接算出前nn项的均值和方差呢?

二、理论推导

\quad定义均值数组mm方差乘上当前长度nn的数组SSmn=i=1nxin,Sn=i=1n(ximn)2m_n = \frac{\sum_{i=1}^nx_i}{n}, S_n=\sum_{i=1}^n(x_i-m_n)^2
首先容易得到均值的递推式子:mn=i=1nxin=i=1n1xi+xnn=n1nmn1+1nxnm_n= \frac{\sum_{i=1}^nx_i}{n}= \frac{\sum_{i=1}^{n-1}x_i+x_n}{n}=\frac{n-1}{n}m_{n-1}+\frac{1}{n}x_n
将上述式子代入可以得到ximn=xi(n1nmn1+1nxn)=ximn11n(xnmn1)x_i-m_n=x_i-(\frac{n-1}{n}m_{n-1}+\frac{1}{n}x_n)=x_i-m_{n-1}-\frac{1}{n}(x_n-m_{n-1}),当i=ni=n时得到xnmn=n1n(xnmn1)x_n-m_n=\frac{n-1}{n}(x_n-m_{n-1})
有了这些辅助,接下来我们尝试推到SS的递推式:
Sn=i=1n(ximn)2=i=1n1(ximn)2+(xnmn)2=i=1n1(ximn)2+(n1n)2(xnmn1)2=i=1n1[ximn11n(xnmn1)]2+(n1n)2(xnmn1)2=i=1n1(ximn1)2+[n1n2+(n1)2n2](xnmn1)2=Sn1+n1n(xnmn1)2S_n=\sum_{i=1}^n(x_i-m_n)^2 \\ =\sum_{i=1}^{n-1}(x_i-m_n)^2+(x_n-m_n)^2 \\ =\sum_{i=1}^{n-1}(x_i-m_n)^2+(\frac{n-1}{n})^2(x_n-m_{n-1})^2 \\ =\sum_{i=1}^{n-1}[x_i-m_{n-1}-\frac{1}{n}(x_n-m_{n-1})]^2+(\frac{n-1}{n})^2(x_n-m_{n-1})^2 \\ =\sum_{i=1}^{n-1}(x_i-m_{n-1})^2+[\frac{n-1}{n^2}+\frac{(n-1)^2}{n^2}](x_n-m_{n-1})^2 \\ =S_{n-1}+\frac{n-1}{n}(x_n-m_{n-1})^2

至此,我们得到了利用数组前n1n-1项的均值和方差推出前nn项的均值和方差的递推式子,如下:
mn=n1nmn1+1nxnSn=Sn1+n1n(xnmn1)2m_n = \frac{n-1}{n}m_{n-1}+\frac{1}{n}x_n \\ S_n=S_{n-1}+\frac{n-1}{n}(x_n-m_{n-1})^2

三、程序

\quad这里给出Python程序求解实例,给出数组xx,返回其均值数组mm和方差数组SS

def meanAndSquare(x):
    x = [0] + x
    m = [0 for _ in range(len(x))]  # 均值
    S = [0 for _ in range(len(x))]  # 方差乘上当前长度的值
    for i in range(1, len(x)):
        m[i] = ((i - 1) * m[i - 1] + x[i]) / i
        S[i] = S[i - 1] + (i - 1) / i * (x[i] - m[i - 1]) ** 2
    for i in range(1, len(S)):
        S[i] /= i  # 注意需要除上当前长度才是方差
    m, S = m[1:], S[1:]
    return m, S

if __name__ == '__main__':
    x = [1, 2, 3, 6]
    print(meanAndSquare(x))

在这里插入图片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章