from: https://en.m.wikipedia.org/wiki/Algorithms_for_calculating_variance#
方差计算算法在计算统计学中起着重要作用。设计一个好的方差计算算法的关键困难是,方差公式可能涉及平方和,这可能导致数值不稳定,以及在处理大值时出现算术溢出。(p.s. 数值稳定性 )
常规算法
计算大小为N的数据的方差:
, (1.1)
其中为总体方差,
为数据,
为均值,
为数据多少。
由 可以推得
(1.2)
使用贝塞尔校正来计算n个数据的有限样本的总体方差的无偏估计,公式为:
(1.3)
(相当于1.2中的分母的N替换为n-1,分子的N替换为n)
总结:
此算法可以适用于有限样本数的总体方差,只需要把分母的n-1替换成n。但是由于和
可能会非常接近,计算过程中的取舍可能会导致精度问题,因此不推荐在实践过程中使用此算法。
计算偏移数据
方差对于位置参数的变化不会产生变化,利用此特性可以避免上述计算过程中的舍入问题:
根据 p.s. 其中的K可以是任何常数
可以得到新的方差计算公式:
(1.4)
(1.4)中的K越接近均值,则方差的计算结果越精确;实际计算过程中使用数据中的任意值都能够保证方差计算的数值稳定性。
如果的值很小,则其平方和没有问题;相反,如果值很大很大,则必然意味着方差也很大。在任何情况下,公式中的第二项总是小于第一项,因此不可能发生抵消。
算法中的K值设定为数据中的第一项,下面给出python代码:
def shifted_data_variance(data):
if len(data) < 2:
return 0.0
K = data[0]
n = Ex = Ex2 = 0.0
for x in data:
n += 1
Ex += x - K
Ex2 += (x - K) ** 2
variance = (Ex2 - Ex**2 / n) / (n - 1)
# use n instead of (n-1) if want to compute the exact variance of the given data
# use (n-1) if data are samples of a larger population
return variance
p.s. 计算数据精确值时把替换为
;计算大数据量样本时使用
。
此方法也可用于增量计算(指一部分数据发生变化时,只计算变化部分的数据而无需重复计算全部数据),下面给出python代码:
##############################################################
## 这里是参数设置
##执行增量计算需要设置好位置参数K、均值Ex、Ex2和已经计算的数据个数
##默认情况下参数为0,此时表示还未计算方差
K = Ex = Ex2 = 0.0
n = 0
##############################################################
def add_variable(x): #增加数据(单个)
global K, n, Ex, Ex2
if n == 0:
K = x
n += 1
Ex += x - K
Ex2 += (x - K) ** 2
def remove_variable(x): #减少数据(单个)
global K, n, Ex, Ex2
n -= 1
Ex -= x - K
Ex2 -= (x - K) ** 2
def get_mean():
global K, n, Ex
return K + Ex / n
def get_variance():
global n, Ex, Ex2
return (Ex2 - Ex**2 / n) / (n - 1)
##############################################################
##执行方式:
## example. data = [1,2,3,4,5,6]
##1.依次加入data中的数据
data = [1,2,3,4,5,6]
for x in data: add_variable(x)
print( get_mean() )
print( get_variance() )
##2.假设已经使用shifted_data_variance计算出了data中前面5个元素的方差
## K = 1 ; Ex = 10.0 ;Ex2 = 30.0 ; n = 5
K,Ex,Ex2,n = (1,10.0,30.0,5)
add_variable(6) #增量计算,加入第6个元素
print( get_mean() )
print( get_variance() )
两步算法
一个替代方案是,使用不同的方差公式。同样的,第一步计算样本均值:
第二步,根据均值计算差的平方和:
, 其中s表示标准差。python代码:
def two_pass_variance(data):
n = len(data)
mean = sum(data) / n
variance = sum([(x - mean) ** 2 for x in data]) / (n - 1)
return variance
Welford 在线算法
此算法计算时,样本数据 只需要使用一次,这样可以减少数据存储。算法的主要思想是建立起递推关系式。(下面均为计算第n个样本数据时的均值和方差)
均值:
有偏方差:
无偏估计:
需要注意的是上面的计算方法存在数值不稳定问题,记 更好的计算方法如下:
均值:
有偏方差:
无偏估计:
公式推导:
(均值推导略)由方差 可知,
和
。 从而得到
和
, 两个结合可以得到
,
又根据均值 ,
所以 , 两边同乘
, 得到
,
又因为 根据均值公式
未完待续…