001: /*
002: * Copyright 2003-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.math.stat.descriptive.moment;
017:
018: import java.io.Serializable;
019:
020: import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
021:
022: /**
023: * Computes the variance of the available values. By default, the unbiased
024: * "sample variance" definitional formula is used:
025: * <p>
026: * variance = sum((x_i - mean)^2) / (n - 1)
027: * <p>
028: * where mean is the {@link Mean} and <code>n</code> is the number
029: * of sample observations.
030: * <p>
031: * The definitional formula does not have good numerical properties, so
032: * this implementation uses updating formulas based on West's algorithm
033: * as described in <a href="http://doi.acm.org/10.1145/359146.359152">
034: * Chan, T. F. andJ. G. Lewis 1979, <i>Communications of the ACM</i>,
035: * vol. 22 no. 9, pp. 526-531.</a>.
036: * <p>
037: * The "population variance" ( sum((x_i - mean)^2) / n ) can also
038: * be computed using this statistic. The <code>isBiasCorrected</code>
039: * property determines whether the "population" or "sample" value is
040: * returned by the <code>evaluate</code> and <code>getResult</code> methods.
041: * To compute population variances, set this property to <code>false.</code>
042: *
043: * <strong>Note that this implementation is not synchronized.</strong> If
044: * multiple threads access an instance of this class concurrently, and at least
045: * one of the threads invokes the <code>increment()</code> or
046: * <code>clear()</code> method, it must be synchronized externally.
047: *
048: * @version $Revision: 348519 $ $Date: 2005-11-23 12:12:18 -0700 (Wed, 23 Nov 2005) $
049: */
050: public class Variance extends AbstractStorelessUnivariateStatistic
051: implements Serializable {
052:
053: /** Serializable version identifier */
054: private static final long serialVersionUID = -9111962718267217978L;
055:
056: /** SecondMoment is used in incremental calculation of Variance*/
057: protected SecondMoment moment = null;
058:
059: /**
060: * Boolean test to determine if this Variance should also increment
061: * the second moment, this evaluates to false when this Variance is
062: * constructed with an external SecondMoment as a parameter.
063: */
064: protected boolean incMoment = true;
065:
066: /**
067: * Determines whether or not bias correction is applied when computing the
068: * value of the statisic. True means that bias is corrected. See
069: * {@link Variance} for details on the formula.
070: */
071: private boolean isBiasCorrected = true;
072:
073: /**
074: * Constructs a Variance with default (true) <code>isBiasCorrected</code>
075: * property.
076: */
077: public Variance() {
078: moment = new SecondMoment();
079: }
080:
081: /**
082: * Constructs a Variance based on an external second moment.
083: *
084: * @param m2 the SecondMoment (Thrid or Fourth moments work
085: * here as well.)
086: */
087: public Variance(final SecondMoment m2) {
088: incMoment = false;
089: this .moment = m2;
090: }
091:
092: /**
093: * Constructs a Variance with the specified <code>isBiasCorrected</code>
094: * property
095: *
096: * @param isBiasCorrected setting for bias correction - true means
097: * bias will be corrected and is equivalent to using the argumentless
098: * constructor
099: */
100: public Variance(boolean isBiasCorrected) {
101: moment = new SecondMoment();
102: this .isBiasCorrected = isBiasCorrected;
103: }
104:
105: /**
106: * Constructs a Variance with the specified <code>isBiasCorrected</code>
107: * property and the supplied external second moment.
108: *
109: * @param isBiasCorrected setting for bias correction - true means
110: * bias will be corrected
111: * @param m2 the SecondMoment (Thrid or Fourth moments work
112: * here as well.)
113: */
114: public Variance(boolean isBiasCorrected, SecondMoment m2) {
115: incMoment = false;
116: this .moment = m2;
117: this .isBiasCorrected = isBiasCorrected;
118: }
119:
120: /**
121: * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#increment(double)
122: */
123: public void increment(final double d) {
124: if (incMoment) {
125: moment.increment(d);
126: }
127: }
128:
129: /**
130: * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getResult()
131: */
132: public double getResult() {
133: if (moment.n == 0) {
134: return Double.NaN;
135: } else if (moment.n == 1) {
136: return 0d;
137: } else {
138: if (isBiasCorrected) {
139: return moment.m2 / ((double) moment.n - 1d);
140: } else {
141: return moment.m2 / ((double) moment.n);
142: }
143: }
144: }
145:
146: /**
147: * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#getN()
148: */
149: public long getN() {
150: return moment.getN();
151: }
152:
153: /**
154: * @see org.apache.commons.math.stat.descriptive.StorelessUnivariateStatistic#clear()
155: */
156: public void clear() {
157: if (incMoment) {
158: moment.clear();
159: }
160: }
161:
162: /**
163: * Returns the variance of the entries in the input array, or
164: * <code>Double.NaN</code> if the array is empty.
165: * <p>
166: * See {@link Variance} for details on the computing algorithm.
167: * <p>
168: * Returns 0 for a single-value (i.e. length = 1) sample.
169: * <p>
170: * Throws <code>IllegalArgumentException</code> if the array is null.
171: * <p>
172: * Does not change the internal state of the statistic.
173: *
174: * @param values the input array
175: * @return the variance of the values or Double.NaN if length = 0
176: * @throws IllegalArgumentException if the array is null
177: */
178: public double evaluate(final double[] values) {
179: if (values == null) {
180: throw new IllegalArgumentException(
181: "input values array is null");
182: }
183: return evaluate(values, 0, values.length);
184: }
185:
186: /**
187: * Returns the variance of the entries in the specified portion of
188: * the input array, or <code>Double.NaN</code> if the designated subarray
189: * is empty.
190: * <p>
191: * See {@link Variance} for details on the computing algorithm.
192: * <p>
193: * Returns 0 for a single-value (i.e. length = 1) sample.
194: * <p>
195: * Does not change the internal state of the statistic.
196: * <p>
197: * Throws <code>IllegalArgumentException</code> if the array is null.
198: *
199: * @param values the input array
200: * @param begin index of the first array element to include
201: * @param length the number of elements to include
202: * @return the variance of the values or Double.NaN if length = 0
203: * @throws IllegalArgumentException if the array is null or the array index
204: * parameters are not valid
205: */
206: public double evaluate(final double[] values, final int begin,
207: final int length) {
208:
209: double var = Double.NaN;
210:
211: if (test(values, begin, length)) {
212: clear();
213: if (length == 1) {
214: var = 0.0;
215: } else if (length > 1) {
216: Mean mean = new Mean();
217: double m = mean.evaluate(values, begin, length);
218: var = evaluate(values, m, begin, length);
219: }
220: }
221: return var;
222: }
223:
224: /**
225: * Returns the variance of the entries in the specified portion of
226: * the input array, using the precomputed mean value. Returns
227: * <code>Double.NaN</code> if the designated subarray is empty.
228: * <p>
229: * See {@link Variance} for details on the computing algorithm.
230: * <p>
231: * The formula used assumes that the supplied mean value is the arithmetic
232: * mean of the sample data, not a known population parameter. This method
233: * is supplied only to save computation when the mean has already been
234: * computed.
235: * <p>
236: * Returns 0 for a single-value (i.e. length = 1) sample.
237: * <p>
238: * Throws <code>IllegalArgumentException</code> if the array is null.
239: * <p>
240: * Does not change the internal state of the statistic.
241: *
242: * @param values the input array
243: * @param mean the precomputed mean value
244: * @param begin index of the first array element to include
245: * @param length the number of elements to include
246: * @return the variance of the values or Double.NaN if length = 0
247: * @throws IllegalArgumentException if the array is null or the array index
248: * parameters are not valid
249: */
250: public double evaluate(final double[] values, final double mean,
251: final int begin, final int length) {
252:
253: double var = Double.NaN;
254:
255: if (test(values, begin, length)) {
256: if (length == 1) {
257: var = 0.0;
258: } else if (length > 1) {
259: double accum = 0.0;
260: double accum2 = 0.0;
261: for (int i = begin; i < begin + length; i++) {
262: accum += Math.pow((values[i] - mean), 2.0);
263: accum2 += (values[i] - mean);
264: }
265: if (isBiasCorrected) {
266: var = (accum - (Math.pow(accum2, 2) / ((double) length)))
267: / (double) (length - 1);
268: } else {
269: var = (accum - (Math.pow(accum2, 2) / ((double) length)))
270: / (double) length;
271: }
272: }
273: }
274: return var;
275: }
276:
277: /**
278: * Returns the variance of the entries in the input array, using the
279: * precomputed mean value. Returns <code>Double.NaN</code> if the array
280: * is empty.
281: * <p>
282: * See {@link Variance} for details on the computing algorithm.
283: * <p>
284: * If <code>isBiasCorrected</code> is <code>true</code> the formula used
285: * assumes that the supplied mean value is the arithmetic mean of the
286: * sample data, not a known population parameter. If the mean is a known
287: * population parameter, or if the "population" version of the variance is
288: * desired, set <code>isBiasCorrected</code> to <code>false</code> before
289: * invoking this method.
290: * <p>
291: * Returns 0 for a single-value (i.e. length = 1) sample.
292: * <p>
293: * Throws <code>IllegalArgumentException</code> if the array is null.
294: * <p>
295: * Does not change the internal state of the statistic.
296: *
297: * @param values the input array
298: * @param mean the precomputed mean value
299: * @return the variance of the values or Double.NaN if the array is empty
300: * @throws IllegalArgumentException if the array is null
301: */
302: public double evaluate(final double[] values, final double mean) {
303: return evaluate(values, mean, 0, values.length);
304: }
305:
306: /**
307: * @return Returns the isBiasCorrected.
308: */
309: public boolean isBiasCorrected() {
310: return isBiasCorrected;
311: }
312:
313: /**
314: * @param isBiasCorrected The isBiasCorrected to set.
315: */
316: public void setBiasCorrected(boolean isBiasCorrected) {
317: this.isBiasCorrected = isBiasCorrected;
318: }
319:
320: }
|