diff --git a/src/java/org/apache/commons/math/stat/descriptive/moment/Variance.java b/src/java/org/apache/commons/math/stat/descriptive/moment/Variance.java index b9781b7a0..c8879ae94 100644 --- a/src/java/org/apache/commons/math/stat/descriptive/moment/Variance.java +++ b/src/java/org/apache/commons/math/stat/descriptive/moment/Variance.java @@ -20,7 +20,8 @@ import java.io.Serializable; import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic; /** - * Computes the (unbiased) sample variance. Uses the definitional formula: + * Computes the variance of the available values. By default, the unbiased + * "sample variance" definitional formula is used: *

* variance = sum((x_i - mean)^2) / (n - 1) *

@@ -32,13 +33,19 @@ import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStati * as described in * Chan, T. F. andJ. G. Lewis 1979, Communications of the ACM, * vol. 22 no. 9, pp. 526-531.. -*

+ *

+ * The "population variance" ( sum((x_i - mean)^2) / n ) can also + * be computed using this statistic. The isBiasCorrected + * property determines whether the "population" or "sample" value is + * returned by the evaluate and getResult methods. + * To compute population variances, set this property to false. + * * Note that this implementation is not synchronized. If * multiple threads access an instance of this class concurrently, and at least * one of the threads invokes the increment() or * clear() method, it must be synchronized externally. * - * @version $Revision: 1.1 $ $Date: 2004/10/08 05:08:17 $ + * @version $Revision: 1.2 $ $Date: 2004/10/10 20:40:52 $ */ public class Variance extends AbstractStorelessUnivariateStatistic implements Serializable { @@ -54,6 +61,13 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se * constructed with an external SecondMoment as a parameter. */ protected boolean incMoment = true; + + /** + * Determines whether or not bias correction is applied when computing the + * value of the statisic. True means that bias is corrected. See + * {@link Variance} for details on the formula. + */ + private boolean isBiasCorrected = true; /** * Constructs a Variance. @@ -64,6 +78,7 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se /** * Constructs a Variance based on an external second moment. + * * @param m2 the SecondMoment (Thrid or Fourth moments work * here as well.) */ @@ -71,6 +86,36 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se incMoment = false; this.moment = m2; } + + /** + * Constructs a Variance with the specified isBiasCorrected + * property + * + * @param isBiasCorrected setting for bias correction - true means + * bias will be corrected and is equivalent to using the argumentless + * constructor + */ + public Variance(boolean isBiasCorrected) { + moment = new SecondMoment(); + this.isBiasCorrected = isBiasCorrected; + } + + /** + * Constructs a Variance with the specified isBiasCorrected + * property and the supplied external second moment. + * + * @param isBiasCorrected setting for bias correction - true means + * bias will be corrected and is equivalent to using the argumentless + * constructor + * @param m2 the SecondMoment (Thrid or Fourth moments work + * here as well.) + */ + public Variance(boolean isBiasCorrected, SecondMoment m2) { + incMoment = false; + this.moment = m2; + this.isBiasCorrected = isBiasCorrected; + } + /** * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#increment(double) */ @@ -89,7 +134,11 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se } else if (moment.n == 1) { return 0d; } else { - return moment.m2 / ((double) moment.n - 1d); + if (isBiasCorrected) { + return moment.m2 / ((double) moment.n - 1d); + } else { + return moment.m2 / ((double) moment.n); + } } } @@ -210,8 +259,13 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se accum += Math.pow((values[i] - mean), 2.0); accum2 += (values[i] - mean); } - var = (accum - (Math.pow(accum2, 2) / ((double) length))) / - (double) (length - 1); + if (isBiasCorrected) { + var = (accum - (Math.pow(accum2, 2) / ((double) length))) / + (double) (length - 1); + } else { + var = (accum - (Math.pow(accum2, 2) / ((double) length))) / + (double) length; + } } } return var; @@ -224,10 +278,12 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se *

* See {@link Variance} for details on the computing algorithm. *

- * The formula used assumes that the supplied mean value is the arithmetic - * mean of the sample data, not a known population parameter. This method - * is supplied only to save computation when the mean has already been - * computed. + * If isBiasCorrected is true the formula used + * assumes that the supplied mean value is the arithmetic mean of the + * sample data, not a known population parameter. If the mean is a known + * population parameter, or if the "population" version of the variance is + * desired, set isBiasCorrected to false before + * invoking this method. *

* Returns 0 for a single-value (i.e. length = 1) sample. *

@@ -244,4 +300,18 @@ public class Variance extends AbstractStorelessUnivariateStatistic implements Se return evaluate(values, mean, 0, values.length); } + /** + * @return Returns the isBiasCorrected. + */ + public boolean isBiasCorrected() { + return isBiasCorrected; + } + + /** + * @param isBiasCorrected The isBiasCorrected to set. + */ + public void setBiasCorrected(boolean isBiasCorrected) { + this.isBiasCorrected = isBiasCorrected; + } + } diff --git a/src/test/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java b/src/test/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java index 925d7f9d4..b76b328a7 100644 --- a/src/test/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java +++ b/src/test/org/apache/commons/math/stat/descriptive/moment/VarianceTest.java @@ -24,7 +24,7 @@ import org.apache.commons.math.stat.descriptive.UnivariateStatistic; /** * Test cases for the {@link UnivariateStatistic} class. * - * @version $Revision: 1.1 $ $Date: 2004/10/08 05:08:20 $ + * @version $Revision: 1.2 $ $Date: 2004/10/10 20:40:52 $ */ public class VarianceTest extends StorelessUnivariateStatisticAbstractTest{ @@ -67,5 +67,33 @@ public class VarianceTest extends StorelessUnivariateStatisticAbstractTest{ std.increment(1d); assertEquals(0d, std.getResult(), 0); } + + /** + * Test population version of variance + */ + public void testPopulation() { + double[] values = {-1.0d, 3.1d, 4.0d, -2.1d, 22d, 11.7d, 3d, 14d}; + SecondMoment m = new SecondMoment(); + m.evaluate(values); // side effect is to add values + Variance v1 = new Variance(); + v1.setBiasCorrected(false); + assertEquals(populationVariance(values), v1.evaluate(values), 1E-14); + v1.incrementAll(values); + assertEquals(populationVariance(values), v1.getResult(), 1E-14); + v1 = new Variance(false, m); + assertEquals(populationVariance(values), v1.getResult(), 1E-14); + } + + /** + * Definitional formula for population variance + */ + protected double populationVariance(double[] v) { + double mean = new Mean().evaluate(v); + double sum = 0; + for (int i = 0; i < v.length; i++) { + sum += (v[i] - mean) * (v[i] - mean); + } + return sum / (double) v.length; + } }