標準偏差を計算するために配列は必要ありません。
ポイント数、総和、総二乗和を記録するだけです。配列を保持しなくても、いつでも平均偏差と標準偏差を計算できます。
私があなたの要件を理解したら、色がキーであり、Statistics のインスタンスが値である Map が必要です。
これがあなたのためにそれを行うクラスです。
package statistics;
/**
* Statistics
* @author Michael
* @link http://stackoverflow.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);
}
}