• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package org.apache.commons.math.stat.descriptive.moment;
18 
19 import java.io.Serializable;
20 
21 import org.apache.commons.math.stat.descriptive.AbstractStorelessUnivariateStatistic;
22 import org.apache.commons.math.stat.descriptive.WeightedEvaluation;
23 import org.apache.commons.math.stat.descriptive.summary.Sum;
24 
25 /**
26  * <p>Computes the arithmetic mean of a set of values. Uses the definitional
27  * formula:</p>
28  * <p>
29  * mean = sum(x_i) / n
30  * </p>
31  * <p>where <code>n</code> is the number of observations.
32  * </p>
33  * <p>When {@link #increment(double)} is used to add data incrementally from a
34  * stream of (unstored) values, the value of the statistic that
35  * {@link #getResult()} returns is computed using the following recursive
36  * updating algorithm: </p>
37  * <ol>
38  * <li>Initialize <code>m = </code> the first value</li>
39  * <li>For each additional value, update using <br>
40  *   <code>m = m + (new value - m) / (number of observations)</code></li>
41  * </ol>
42  * <p> If {@link #evaluate(double[])} is used to compute the mean of an array
43  * of stored values, a two-pass, corrected algorithm is used, starting with
44  * the definitional formula computed using the array of stored values and then
45  * correcting this by adding the mean deviation of the data values from the
46  * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing
47  * Sample Means and Variances," Robert F. Ling, Journal of the American
48  * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866. </p>
49  * <p>
50  *  Returns <code>Double.NaN</code> if the dataset is empty.
51  * </p>
52  * <strong>Note that this implementation is not synchronized.</strong> If
53  * multiple threads access an instance of this class concurrently, and at least
54  * one of the threads invokes the <code>increment()</code> or
55  * <code>clear()</code> method, it must be synchronized externally.
56  *
57  * @version $Revision: 1006299 $ $Date: 2010-10-10 16:47:17 +0200 (dim. 10 oct. 2010) $
58  */
59 public class Mean extends AbstractStorelessUnivariateStatistic
60     implements Serializable, WeightedEvaluation {
61 
62     /** Serializable version identifier */
63     private static final long serialVersionUID = -1296043746617791564L;
64 
65     /** First moment on which this statistic is based. */
66     protected FirstMoment moment;
67 
68     /**
69      * Determines whether or not this statistic can be incremented or cleared.
70      * <p>
71      * Statistics based on (constructed from) external moments cannot
72      * be incremented or cleared.</p>
73      */
74     protected boolean incMoment;
75 
76     /** Constructs a Mean. */
Mean()77     public Mean() {
78         incMoment = true;
79         moment = new FirstMoment();
80     }
81 
82     /**
83      * Constructs a Mean with an External Moment.
84      *
85      * @param m1 the moment
86      */
Mean(final FirstMoment m1)87     public Mean(final FirstMoment m1) {
88         this.moment = m1;
89         incMoment = false;
90     }
91 
92     /**
93      * Copy constructor, creates a new {@code Mean} identical
94      * to the {@code original}
95      *
96      * @param original the {@code Mean} instance to copy
97      */
Mean(Mean original)98     public Mean(Mean original) {
99         copy(original, this);
100     }
101 
102     /**
103      * {@inheritDoc}
104      */
105     @Override
increment(final double d)106     public void increment(final double d) {
107         if (incMoment) {
108             moment.increment(d);
109         }
110     }
111 
112     /**
113      * {@inheritDoc}
114      */
115     @Override
clear()116     public void clear() {
117         if (incMoment) {
118             moment.clear();
119         }
120     }
121 
122     /**
123      * {@inheritDoc}
124      */
125     @Override
getResult()126     public double getResult() {
127         return moment.m1;
128     }
129 
130     /**
131      * {@inheritDoc}
132      */
getN()133     public long getN() {
134         return moment.getN();
135     }
136 
137     /**
138      * Returns the arithmetic mean of the entries in the specified portion of
139      * the input array, or <code>Double.NaN</code> if the designated subarray
140      * is empty.
141      * <p>
142      * Throws <code>IllegalArgumentException</code> if the array is null.</p>
143      * <p>
144      * See {@link Mean} for details on the computing algorithm.</p>
145      *
146      * @param values the input array
147      * @param begin index of the first array element to include
148      * @param length the number of elements to include
149      * @return the mean of the values or Double.NaN if length = 0
150      * @throws IllegalArgumentException if the array is null or the array index
151      *  parameters are not valid
152      */
153     @Override
evaluate(final double[] values,final int begin, final int length)154     public double evaluate(final double[] values,final int begin, final int length) {
155         if (test(values, begin, length)) {
156             Sum sum = new Sum();
157             double sampleSize = length;
158 
159             // Compute initial estimate using definitional formula
160             double xbar = sum.evaluate(values, begin, length) / sampleSize;
161 
162             // Compute correction factor in second pass
163             double correction = 0;
164             for (int i = begin; i < begin + length; i++) {
165                 correction += values[i] - xbar;
166             }
167             return xbar + (correction/sampleSize);
168         }
169         return Double.NaN;
170     }
171 
172     /**
173      * Returns the weighted arithmetic mean of the entries in the specified portion of
174      * the input array, or <code>Double.NaN</code> if the designated subarray
175      * is empty.
176      * <p>
177      * Throws <code>IllegalArgumentException</code> if either array is null.</p>
178      * <p>
179      * See {@link Mean} for details on the computing algorithm. The two-pass algorithm
180      * described above is used here, with weights applied in computing both the original
181      * estimate and the correction factor.</p>
182      * <p>
183      * Throws <code>IllegalArgumentException</code> if any of the following are true:
184      * <ul><li>the values array is null</li>
185      *     <li>the weights array is null</li>
186      *     <li>the weights array does not have the same length as the values array</li>
187      *     <li>the weights array contains one or more infinite values</li>
188      *     <li>the weights array contains one or more NaN values</li>
189      *     <li>the weights array contains negative values</li>
190      *     <li>the start and length arguments do not determine a valid array</li>
191      * </ul></p>
192      *
193      * @param values the input array
194      * @param weights the weights array
195      * @param begin index of the first array element to include
196      * @param length the number of elements to include
197      * @return the mean of the values or Double.NaN if length = 0
198      * @throws IllegalArgumentException if the parameters are not valid
199      * @since 2.1
200      */
evaluate(final double[] values, final double[] weights, final int begin, final int length)201     public double evaluate(final double[] values, final double[] weights,
202                            final int begin, final int length) {
203         if (test(values, weights, begin, length)) {
204             Sum sum = new Sum();
205 
206             // Compute initial estimate using definitional formula
207             double sumw = sum.evaluate(weights,begin,length);
208             double xbarw = sum.evaluate(values, weights, begin, length) / sumw;
209 
210             // Compute correction factor in second pass
211             double correction = 0;
212             for (int i = begin; i < begin + length; i++) {
213                 correction += weights[i] * (values[i] - xbarw);
214             }
215             return xbarw + (correction/sumw);
216         }
217         return Double.NaN;
218     }
219 
220     /**
221      * Returns the weighted arithmetic mean of the entries in the input array.
222      * <p>
223      * Throws <code>IllegalArgumentException</code> if either array is null.</p>
224      * <p>
225      * See {@link Mean} for details on the computing algorithm. The two-pass algorithm
226      * described above is used here, with weights applied in computing both the original
227      * estimate and the correction factor.</p>
228      * <p>
229      * Throws <code>IllegalArgumentException</code> if any of the following are true:
230      * <ul><li>the values array is null</li>
231      *     <li>the weights array is null</li>
232      *     <li>the weights array does not have the same length as the values array</li>
233      *     <li>the weights array contains one or more infinite values</li>
234      *     <li>the weights array contains one or more NaN values</li>
235      *     <li>the weights array contains negative values</li>
236      * </ul></p>
237      *
238      * @param values the input array
239      * @param weights the weights array
240      * @return the mean of the values or Double.NaN if length = 0
241      * @throws IllegalArgumentException if the parameters are not valid
242      * @since 2.1
243      */
evaluate(final double[] values, final double[] weights)244     public double evaluate(final double[] values, final double[] weights) {
245         return evaluate(values, weights, 0, values.length);
246     }
247 
248     /**
249      * {@inheritDoc}
250      */
251     @Override
copy()252     public Mean copy() {
253         Mean result = new Mean();
254         copy(this, result);
255         return result;
256     }
257 
258 
259     /**
260      * Copies source to dest.
261      * <p>Neither source nor dest can be null.</p>
262      *
263      * @param source Mean to copy
264      * @param dest Mean to copy to
265      * @throws NullPointerException if either source or dest is null
266      */
copy(Mean source, Mean dest)267     public static void copy(Mean source, Mean dest) {
268         dest.setData(source.getDataRef());
269         dest.incMoment = source.incMoment;
270         dest.moment = source.moment.copy();
271     }
272 }
273