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 * https://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 18 /* 19 * This is not the original file distributed by the Apache Software Foundation 20 * It has been modified by the Hipparchus project 21 */ 22 package org.hipparchus.stat.descriptive.moment; 23 24 import java.io.Serializable; 25 26 import org.hipparchus.exception.MathIllegalArgumentException; 27 import org.hipparchus.exception.NullArgumentException; 28 import org.hipparchus.stat.StatUtils; 29 import org.hipparchus.stat.descriptive.AbstractStorelessUnivariateStatistic; 30 import org.hipparchus.stat.descriptive.AggregatableStatistic; 31 import org.hipparchus.stat.descriptive.WeightedEvaluation; 32 import org.hipparchus.stat.descriptive.summary.Sum; 33 import org.hipparchus.util.MathArrays; 34 import org.hipparchus.util.MathUtils; 35 36 /** 37 * Computes the arithmetic mean of a set of values. Uses the definitional 38 * formula: 39 * <p> 40 * mean = sum(x_i) / n 41 * <p> 42 * where <code>n</code> is the number of observations. 43 * <p> 44 * When {@link #increment(double)} is used to add data incrementally from a 45 * stream of (unstored) values, the value of the statistic that 46 * {@link #getResult()} returns is computed using the following recursive 47 * updating algorithm: 48 * <ol> 49 * <li>Initialize <code>m = </code> the first value</li> 50 * <li>For each additional value, update using <br> 51 * <code>m = m + (new value - m) / (number of observations)</code></li> 52 * </ol> 53 * <p> 54 * If {@link #evaluate(double[])} is used to compute the mean of an array 55 * of stored values, a two-pass, corrected algorithm is used, starting with 56 * the definitional formula computed using the array of stored values and then 57 * correcting this by adding the mean deviation of the data values from the 58 * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing 59 * Sample Means and Variances," Robert F. Ling, Journal of the American 60 * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866. 61 * <p> 62 * Returns <code>Double.NaN</code> if the dataset is empty. Note that 63 * Double.NaN may also be returned if the input includes NaN and / or infinite 64 * values. 65 * <p> 66 * <strong>Note that this implementation is not synchronized.</strong> If 67 * multiple threads access an instance of this class concurrently, and at least 68 * one of the threads invokes the <code>increment()</code> or 69 * <code>clear()</code> method, it must be synchronized externally. 70 */ 71 public class Mean extends AbstractStorelessUnivariateStatistic 72 implements AggregatableStatistic<Mean>, WeightedEvaluation, Serializable { 73 74 /** Serializable version identifier */ 75 private static final long serialVersionUID = 20150412L; 76 77 /** First moment on which this statistic is based. */ 78 protected final FirstMoment moment; 79 80 /** 81 * Determines whether or not this statistic can be incremented or cleared. 82 * <p> 83 * Statistics based on (constructed from) external moments cannot 84 * be incremented or cleared. 85 */ 86 protected final boolean incMoment; 87 88 /** Constructs a Mean. */ 89 public Mean() { 90 moment = new FirstMoment(); 91 incMoment = true; 92 } 93 94 /** 95 * Constructs a Mean with an External Moment. 96 * 97 * @param m1 the moment 98 */ 99 public Mean(final FirstMoment m1) { 100 this.moment = m1; 101 incMoment = false; 102 } 103 104 /** 105 * Copy constructor, creates a new {@code Mean} identical 106 * to the {@code original}. 107 * 108 * @param original the {@code Mean} instance to copy 109 * @throws NullArgumentException if original is null 110 */ 111 public Mean(Mean original) throws NullArgumentException { 112 MathUtils.checkNotNull(original); 113 this.moment = original.moment.copy(); 114 this.incMoment = original.incMoment; 115 } 116 117 /** 118 * {@inheritDoc} 119 * <p> 120 * Note that when {@link #Mean(FirstMoment)} is used to 121 * create a Mean, this method does nothing. In that case, the 122 * FirstMoment should be incremented directly. 123 */ 124 @Override 125 public void increment(final double d) { 126 if (incMoment) { 127 moment.increment(d); 128 } 129 } 130 131 /** {@inheritDoc} */ 132 @Override 133 public void clear() { 134 if (incMoment) { 135 moment.clear(); 136 } 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public double getResult() { 142 return moment.m1; 143 } 144 145 /** {@inheritDoc} */ 146 @Override 147 public long getN() { 148 return moment.getN(); 149 } 150 151 /** {@inheritDoc} */ 152 @Override 153 public void aggregate(Mean other) { 154 MathUtils.checkNotNull(other); 155 if (incMoment) { 156 this.moment.aggregate(other.moment); 157 } 158 } 159 160 /** 161 * Returns the arithmetic mean of the entries in the specified portion of 162 * the input array, or <code>Double.NaN</code> if the designated subarray 163 * is empty. 164 * 165 * @param values the input array 166 * @param begin index of the first array element to include 167 * @param length the number of elements to include 168 * @return the mean of the values or Double.NaN if length = 0 169 * @throws MathIllegalArgumentException if the array is null or the array index 170 * parameters are not valid 171 */ 172 @Override 173 public double evaluate(final double[] values, final int begin, final int length) 174 throws MathIllegalArgumentException { 175 176 if (MathArrays.verifyValues(values, begin, length)) { 177 double sampleSize = length; 178 179 // Compute initial estimate using definitional formula 180 double xbar = StatUtils.sum(values, begin, length) / sampleSize; 181 182 // Compute correction factor in second pass 183 double correction = 0; 184 for (int i = begin; i < begin + length; i++) { 185 correction += values[i] - xbar; 186 } 187 return xbar + (correction / sampleSize); 188 } 189 return Double.NaN; 190 } 191 192 /** 193 * Returns the weighted arithmetic mean of the entries in the specified portion of 194 * the input array, or <code>Double.NaN</code> if the designated subarray 195 * is empty. 196 * <p> 197 * Throws <code>IllegalArgumentException</code> if either array is null. 198 * <p> 199 * See {@link Mean} for details on the computing algorithm. The two-pass algorithm 200 * described above is used here, with weights applied in computing both the original 201 * estimate and the correction factor. 202 * <p> 203 * Throws <code>IllegalArgumentException</code> if any of the following are true: 204 * <ul><li>the values array is null</li> 205 * <li>the weights array is null</li> 206 * <li>the weights array does not have the same length as the values array</li> 207 * <li>the weights array contains one or more infinite values</li> 208 * <li>the weights array contains one or more NaN values</li> 209 * <li>the weights array contains negative values</li> 210 * <li>the start and length arguments do not determine a valid array</li> 211 * </ul> 212 * 213 * @param values the input array 214 * @param weights the weights array 215 * @param begin index of the first array element to include 216 * @param length the number of elements to include 217 * @return the mean of the values or Double.NaN if length = 0 218 * @throws MathIllegalArgumentException if the parameters are not valid 219 */ 220 @Override 221 public double evaluate(final double[] values, final double[] weights, 222 final int begin, final int length) 223 throws MathIllegalArgumentException { 224 225 if (MathArrays.verifyValues(values, weights, begin, length)) { 226 Sum sum = new Sum(); 227 228 // Compute initial estimate using definitional formula 229 double sumw = sum.evaluate(weights,begin,length); 230 double xbarw = sum.evaluate(values, weights, begin, length) / sumw; 231 232 // Compute correction factor in second pass 233 double correction = 0; 234 for (int i = begin; i < begin + length; i++) { 235 correction += weights[i] * (values[i] - xbarw); 236 } 237 return xbarw + (correction/sumw); 238 } 239 return Double.NaN; 240 } 241 242 /** {@inheritDoc} */ 243 @Override 244 public Mean copy() { 245 return new Mean(this); 246 } 247 248 }