Mean.java

  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.  * This is not the original file distributed by the Apache Software Foundation
  19.  * It has been modified by the Hipparchus project
  20.  */
  21. package org.hipparchus.stat.descriptive.moment;

  22. import java.io.Serializable;

  23. import org.hipparchus.exception.MathIllegalArgumentException;
  24. import org.hipparchus.exception.NullArgumentException;
  25. import org.hipparchus.stat.StatUtils;
  26. import org.hipparchus.stat.descriptive.AbstractStorelessUnivariateStatistic;
  27. import org.hipparchus.stat.descriptive.AggregatableStatistic;
  28. import org.hipparchus.stat.descriptive.WeightedEvaluation;
  29. import org.hipparchus.stat.descriptive.summary.Sum;
  30. import org.hipparchus.util.MathArrays;
  31. import org.hipparchus.util.MathUtils;

  32. /**
  33.  * Computes the arithmetic mean of a set of values. Uses the definitional
  34.  * formula:
  35.  * <p>
  36.  * mean = sum(x_i) / n
  37.  * <p>
  38.  * where <code>n</code> is the number of observations.
  39.  * <p>
  40.  * When {@link #increment(double)} is used to add data incrementally from a
  41.  * stream of (unstored) values, the value of the statistic that
  42.  * {@link #getResult()} returns is computed using the following recursive
  43.  * updating algorithm:
  44.  * <ol>
  45.  * <li>Initialize <code>m = </code> the first value</li>
  46.  * <li>For each additional value, update using <br>
  47.  *   <code>m = m + (new value - m) / (number of observations)</code></li>
  48.  * </ol>
  49.  * <p>
  50.  * If {@link #evaluate(double[])} is used to compute the mean of an array
  51.  * of stored values, a two-pass, corrected algorithm is used, starting with
  52.  * the definitional formula computed using the array of stored values and then
  53.  * correcting this by adding the mean deviation of the data values from the
  54.  * arithmetic mean. See, e.g. "Comparison of Several Algorithms for Computing
  55.  * Sample Means and Variances," Robert F. Ling, Journal of the American
  56.  * Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. 859-866.
  57.  * <p>
  58.  * Returns <code>Double.NaN</code> if the dataset is empty. Note that
  59.  * Double.NaN may also be returned if the input includes NaN and / or infinite
  60.  * values.
  61.  * <p>
  62.  * <strong>Note that this implementation is not synchronized.</strong> If
  63.  * multiple threads access an instance of this class concurrently, and at least
  64.  * one of the threads invokes the <code>increment()</code> or
  65.  * <code>clear()</code> method, it must be synchronized externally.
  66.  */
  67. public class Mean extends AbstractStorelessUnivariateStatistic
  68.     implements AggregatableStatistic<Mean>, WeightedEvaluation, Serializable {

  69.     /** Serializable version identifier */
  70.     private static final long serialVersionUID = 20150412L;

  71.     /** First moment on which this statistic is based. */
  72.     protected final FirstMoment moment;

  73.     /**
  74.      * Determines whether or not this statistic can be incremented or cleared.
  75.      * <p>
  76.      * Statistics based on (constructed from) external moments cannot
  77.      * be incremented or cleared.
  78.      */
  79.     protected final boolean incMoment;

  80.     /** Constructs a Mean. */
  81.     public Mean() {
  82.         moment = new FirstMoment();
  83.         incMoment = true;
  84.     }

  85.     /**
  86.      * Constructs a Mean with an External Moment.
  87.      *
  88.      * @param m1 the moment
  89.      */
  90.     public Mean(final FirstMoment m1) {
  91.         this.moment = m1;
  92.         incMoment = false;
  93.     }

  94.     /**
  95.      * Copy constructor, creates a new {@code Mean} identical
  96.      * to the {@code original}.
  97.      *
  98.      * @param original the {@code Mean} instance to copy
  99.      * @throws NullArgumentException if original is null
  100.      */
  101.     public Mean(Mean original) throws NullArgumentException {
  102.         MathUtils.checkNotNull(original);
  103.         this.moment    = original.moment.copy();
  104.         this.incMoment = original.incMoment;
  105.     }

  106.     /**
  107.      * {@inheritDoc}
  108.      * <p>
  109.      * Note that when {@link #Mean(FirstMoment)} is used to
  110.      * create a Mean, this method does nothing. In that case, the
  111.      * FirstMoment should be incremented directly.
  112.      */
  113.     @Override
  114.     public void increment(final double d) {
  115.         if (incMoment) {
  116.             moment.increment(d);
  117.         }
  118.     }

  119.     /** {@inheritDoc} */
  120.     @Override
  121.     public void clear() {
  122.         if (incMoment) {
  123.             moment.clear();
  124.         }
  125.     }

  126.     /** {@inheritDoc} */
  127.     @Override
  128.     public double getResult() {
  129.         return moment.m1;
  130.     }

  131.     /** {@inheritDoc} */
  132.     @Override
  133.     public long getN() {
  134.         return moment.getN();
  135.     }

  136.     /** {@inheritDoc} */
  137.     @Override
  138.     public void aggregate(Mean other) {
  139.         MathUtils.checkNotNull(other);
  140.         if (incMoment) {
  141.             this.moment.aggregate(other.moment);
  142.         }
  143.     }

  144.     /**
  145.      * Returns the arithmetic mean of the entries in the specified portion of
  146.      * the input array, or <code>Double.NaN</code> if the designated subarray
  147.      * is empty.
  148.      *
  149.      * @param values the input array
  150.      * @param begin index of the first array element to include
  151.      * @param length the number of elements to include
  152.      * @return the mean of the values or Double.NaN if length = 0
  153.      * @throws MathIllegalArgumentException if the array is null or the array index
  154.      *  parameters are not valid
  155.      */
  156.     @Override
  157.     public double evaluate(final double[] values, final int begin, final int length)
  158.         throws MathIllegalArgumentException {

  159.         if (MathArrays.verifyValues(values, begin, length)) {
  160.             double sampleSize = length;

  161.             // Compute initial estimate using definitional formula
  162.             double xbar = StatUtils.sum(values, begin, length) / sampleSize;

  163.             // Compute correction factor in second pass
  164.             double correction = 0;
  165.             for (int i = begin; i < begin + length; i++) {
  166.                 correction += values[i] - xbar;
  167.             }
  168.             return xbar + (correction / sampleSize);
  169.         }
  170.         return Double.NaN;
  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.
  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.
  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>
  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 MathIllegalArgumentException if the parameters are not valid
  199.      */
  200.     @Override
  201.     public double evaluate(final double[] values, final double[] weights,
  202.                            final int begin, final int length)
  203.         throws MathIllegalArgumentException {

  204.         if (MathArrays.verifyValues(values, weights, begin, length)) {
  205.             Sum sum = new Sum();

  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.             // Compute correction factor in second pass
  210.             double correction = 0;
  211.             for (int i = begin; i < begin + length; i++) {
  212.                 correction += weights[i] * (values[i] - xbarw);
  213.             }
  214.             return xbarw + (correction/sumw);
  215.         }
  216.         return Double.NaN;
  217.     }

  218.     /** {@inheritDoc} */
  219.     @Override
  220.     public Mean copy() {
  221.         return new Mean(this);
  222.     }

  223. }