计算标准差的在线算法

Posted

技术标签:

【中文标题】计算标准差的在线算法【英文标题】:Online algorithm for calculating standard deviation 【发布时间】:2012-08-12 07:13:30 【问题描述】:

通常,我有一个技术性问题,但我会用一个数球的例子为你简化它。

假设我有不同颜色的球和为每种颜色保留的数组的一个索引(初始化为全 0)。每次我拿起一个球,我都会将相应的索引增加 1。

球是随机挑选的,我一次只能挑选一个球。我唯一的目的是计算每种颜色的球数,直到我用完球。

我想计算不同颜色的球的数量的标准偏差,在我数它们的时候。在计算完所有球后,我不想通过再次遍历数组来计算它。

可视化:

随机排列的小球:BBGRRYYBBGGGGGGB(每个字母代表一种颜色的第一个字母) 从 0 到 3 的数组索引分别对应于颜色 B、G、R 和 Y。 当我完成挑选球后,我的数组看起来像[5,7,2,2]

在获得最终数组后计算标准偏差非常简单,但我想在填充此数组时进行计算。

我想用 Java 做,我有大约 1000 种颜色。

实现它的最有效方法是什么?或者在得到最终数组之前有没有办法做到这一点?

【问题讨论】:

这称为en.wikipedia.org/wiki/Online_algorithm。 我不太明白标准差对颜色意味着什么。绿色离红色比离蓝色更远吗? 意义不相关,我只是举个例子来简化我的情况。 @meriton 我相信 OP 表示每种颜色的 频率 的标准差。 正确,我正在数每种颜色的球。 【参考方案1】:

由于使用总和计算平均值和标准差,您可以轻松地为这些实现适当的累加器。然后,当您需要实际值时,完成其余的计算(尤其是除法)。

平方和是棘手的部分,因为您要为每个输入增加一个频率。解决这个问题的一种方法是保持迄今为止看到的每种颜色的计数(使用适当的数据结构)。然后,当您在输入中看到一种颜色时,您可以减去它之前的平方并重新添加新的平方(或等效地将两个平方的差添加到您的累加器中)。

我将把它留给读者来实现这里描述的算法。

【讨论】:

“减去之前的正方形,然后重新添加新的正方形”。所以你做-=n*n; += (n+1)*(n+1)。效率有点低,你可以改用+= 2*n+1 @MSalters 阅读:“或等效地......”【参考方案2】:

您不需要数组来计算标准差。

只需跟踪点数、总和和总平方和。您可以随时计算均值和标准差,而无需保留数组。

如果我了解您的要求,您将需要一个 Map,其中颜色是键,Statistics 实例是值。

这是一个为你做这件事的课程。

package statistics;

/**
 * Statistics
 * @author Michael
 * @link http://***.com/questions/11978667/online-algorithm-for-calculating-standrd-deviation/11978689#11978689
 * @since 8/15/12 7:34 PM
 */
public class Statistics 

    private int n;
    private double sum;
    private double sumsq;

    public void reset() 
        this.n = 0;
        this.sum = 0.0;
        this.sumsq = 0.0;
    

    public synchronized void addValue(double x) 
        ++this.n;
        this.sum += x;
        this.sumsq += x*x;
    

    public synchronized double calculateMean() 
        double mean = 0.0;
        if (this.n > 0) 
            mean = this.sum/this.n;
        
        return mean;
    

    public synchronized double calculateVariance() 
       double deviation = calculateStandardDeviation();
        return deviation*deviation;
    

    public synchronized double calculateStandardDeviation() 
        double deviation = 0.0;
        if (this.n > 1) 
            deviation = Math.sqrt((this.sumsq - this.sum*this.sum/this.n)/(this.n-1));
        
        return deviation;
    

这是它的单元测试:

package statistics;

import org.junit.Assert;
import org.junit.Test;

/**
 * StatisticsTest
 * @author Michael
 * @link http://www.wolframalpha.com/input/?i=variance%281%2C+2%2C+3%2C+4%2C+5%2C+6%29&a=*C.variance-_*Variance-
 * @since 8/15/12 7:42 PM
 */
public class StatisticsTest 

    private static final double TOLERANCE = 1.0E-9;

    @Test
    public void testCalculateMean() 
        double [] values = new double[] 
            1.0, 2.0, 3.0, 4.0, 5.0, 6.0
        ;
        Statistics stats = new Statistics();
        for (double value : values) 
            stats.addValue(value);
        
        double expected = 3.5;
        Assert.assertEquals(expected, stats.calculateMean(), TOLERANCE);
    

    @Test
    public void testCalculateVariance() 
        double [] values = new double[] 
                1.0, 2.0, 3.0, 4.0, 5.0, 6.0
        ;
        Statistics stats = new Statistics();
        for (double value : values) 
            stats.addValue(value);
        
        double expected = 3.5;
        Assert.assertEquals(expected, stats.calculateVariance(), TOLERANCE);
    


    @Test
    public void testCalculateStandardDeviation() 
        double [] values = new double[] 
                1.0, 2.0, 3.0, 4.0, 5.0, 6.0
        ;
        Statistics stats = new Statistics();
        for (double value : values) 
            stats.addValue(value);
        
        double expected = Math.sqrt(3.5);
        Assert.assertEquals(expected, stats.calculateStandardDeviation(), TOLERANCE);
    


【讨论】:

如何在不知道每种颜色有多少个球的情况下跟踪总平方和? 您需要一个数组来跟踪每种颜色的计数。但是,您不需要从头开始重新计算 avg 和 stddev。由于您知道当前球的颜色,您可以减去它的前一个方块,然后添加新的方块。 @duffymo 我不认为你的答案是完整的。部分问题是 OP 需要在读取下一个输入时更改以前的值。 @Code-Guru,这完全正确。当我计算标准偏差时,我没有准备好数组。这是我的问题的核心,这个答案没有解决这个问题。

以上是关于计算标准差的在线算法的主要内容,如果未能解决你的问题,请参考以下文章

算法 A 求稳健平均值和稳健标准差

算法 A 求稳健平均值和稳健标准差

如何用excel计算标准差的方法

Pandas计算标准差

方差和标准差的意义

方差和标准差的意义