快速計算數組中前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))

在這裏插入圖片描述

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