当前位置:编程学习 > JAVA >>

Java 实现样本方差的计算

在一些统计或者排序的算法中,常常要用到样本方差这个东西,来判断一组数据的离散程度。

这是样本方差的公式:

 s^2=\frac{\sum(X_i-\bar X)^2}{N-1}

 

  然而,在计算机编程中,往往需要计算运行方差(running variance),因为样本的个数总是的在不断变化的,确切将是不断递增;如果每次增加,都要重新计算平均值,再按次公式,计算出方差;虽可以实现,但计算量会随着数据的增长变的太大。

      因此,递推的公式就显得格外重要;通过n-1个样本时的方差值,和新增的样本,就能得到此时这N个样本的方差;这样计算量不会变同时保持在一个很小的值,可大大提高程序的计算效率。递推公式如下:

      Mn = Mn-1+ (xn - Mn-1)/n


      Sn = Sn-1 + (xn - Mn-1)*(xn - Mn)

      Mn为平均值,初始时: M1 = x1,  S1 = 0 (此等式的推导证明,我后面给出),而样本方差 s =Sn/(n - 1)

      下面是我自己给出的简单实现(若有更好的实现,请不吝赐教)

 

01 package com.mycode.math; 

02   

03 public final class RunningVariance { 

04     private int count;// 样本的个数 

05     private double mk;// 平均值 

06     private double sk;// Sn 

07     private double runVar;// 样本方差 

08   

09     public RunningVariance() { 

10         this(0, 0.0, 0.0); 

11     } 

12   

13     public RunningVariance(int count, double mk, double sk) { 

14         this.count = count; 

15         this.mk = mk; 

16         this.sk = sk; 

17         recomputeRunVar(); 

18     } 

19   

20     public double getMk() { 

21         return mk; 

22     } 

23   

24     public double getSk() { 

25         return sk; 

26     } 

27   

28     /** 

29      * 获取运行时样本方差 

30      *  

31      * @return 

32      */

33     public synchronized double getRunningVariance() { 

34         return runVar; 

35     } 

36   

37     /** 

38      * 增加样本 

39      *  

40      * @param sample 

41      */

42     public synchronized void addSample(double sample) { 

43         if (++count == 1) { 

44             mk = sample; 

45             sk = 0.0; 

46         } else { 

47             double oldmk = mk; 

48             double diff = sample - oldmk; 

49             mk += diff / count; 

50             sk += diff * (sample - mk); 

51         } 

52         recomputeRunVar(); 

53     } 

54   

55     /** 

56      * 移除样本 

57      *  

58      * @param sample 

59      */

60     public synchronized void removeSample(double sample) { 

61         int oldCount = getCount(); 

62         double oldmk = mk; 

63         if (oldCount == 0) { 

64             throw new IllegalStateException(); 

65         } 

66         if (--count == 0) { 

67             mk = Double.NaN; 

68             sk = Double.NaN; 

69         } else { 

70             mk = (oldCount * oldmk - sample) / (oldCount - 1); 

71             sk -= (sample - mk) * (sample - oldmk); 

72         } 

73         recomputeRunVar(); 

74     } 

75   

76     private synchronized void recomputeRunVar() { 

77         int count = getCount(); 

78         runVar = count > 1 ? sk / (count - 1) : Double.NaN; 

79         // 若需要计算标准差 

80         // runVar = count > 1 ? Math.sqrt(sk / (count - 1)) : Double.NaN; 

81     } 

82   

83     public synchronized int getCount() { 

84         return count; 

85     } 

86 }


         对于递推公式  Sn = Sn-1 + (xn - Mn-1)*(xn - Mn),我自己做了个简单的推导证明,如下图:

        另:图中所提的 等式1  即是 平均数的递推公式:Mn = Mn-1+ (xn - Mn-1)/n

 \


摘自 Breath_L的博客
 

补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,