View Javadoc
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.math4.legacy.stat;
18  
19  import java.util.List;
20  
21  import org.apache.commons.math4.legacy.exception.DimensionMismatchException;
22  import org.apache.commons.math4.legacy.exception.MathIllegalArgumentException;
23  import org.apache.commons.math4.legacy.exception.NoDataException;
24  import org.apache.commons.math4.legacy.exception.NotPositiveException;
25  import org.apache.commons.math4.legacy.exception.NullArgumentException;
26  import org.apache.commons.math4.legacy.exception.NumberIsTooSmallException;
27  import org.apache.commons.math4.legacy.exception.util.LocalizedFormats;
28  import org.apache.commons.math4.legacy.stat.descriptive.DescriptiveStatistics;
29  import org.apache.commons.math4.legacy.stat.descriptive.UnivariateStatistic;
30  import org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean;
31  import org.apache.commons.math4.legacy.stat.descriptive.moment.Mean;
32  import org.apache.commons.math4.legacy.stat.descriptive.moment.Variance;
33  import org.apache.commons.math4.legacy.stat.descriptive.rank.Max;
34  import org.apache.commons.math4.legacy.stat.descriptive.rank.Min;
35  import org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile;
36  import org.apache.commons.math4.legacy.stat.descriptive.summary.Product;
37  import org.apache.commons.math4.legacy.stat.descriptive.summary.Sum;
38  import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs;
39  import org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfSquares;
40  
41  /**
42   * StatUtils provides static methods for computing statistics based on data
43   * stored in double[] arrays.
44   */
45  public final class StatUtils {
46  
47      /** sum. */
48      private static final UnivariateStatistic SUM = new Sum();
49  
50      /** sumSq. */
51      private static final UnivariateStatistic SUM_OF_SQUARES = new SumOfSquares();
52  
53      /** prod. */
54      private static final UnivariateStatistic PRODUCT = new Product();
55  
56      /** sumLog. */
57      private static final UnivariateStatistic SUM_OF_LOGS = new SumOfLogs();
58  
59      /** min. */
60      private static final UnivariateStatistic MIN = new Min();
61  
62      /** max. */
63      private static final UnivariateStatistic MAX = new Max();
64  
65      /** mean. */
66      private static final UnivariateStatistic MEAN = new Mean();
67  
68      /** variance. */
69      private static final Variance VARIANCE = new Variance();
70  
71      /** percentile. */
72      private static final Percentile PERCENTILE = new Percentile();
73  
74      /** geometric mean. */
75      private static final GeometricMean GEOMETRIC_MEAN = new GeometricMean();
76  
77      /**
78       * Private Constructor.
79       */
80      private StatUtils() {
81      }
82  
83      /**
84       * Returns the sum of the values in the input array, or
85       * <code>Double.NaN</code> if the array is empty.
86       * <p>
87       * Throws <code>IllegalArgumentException</code> if the input array is null.
88       *
89       * @param values  array of values to sum
90       * @return the sum of the values or <code>Double.NaN</code> if the array is empty
91       * @throws MathIllegalArgumentException if the array is null
92       */
93      public static double sum(final double[] values) throws MathIllegalArgumentException {
94          return SUM.evaluate(values);
95      }
96  
97      /**
98       * Returns the sum of the entries in the specified portion of
99       * the input array, or <code>Double.NaN</code> if the designated subarray is empty.
100      * <p>
101      * Throws <code>IllegalArgumentException</code> if the array is null.
102      *
103      * @param values the input array
104      * @param begin index of the first array element to include
105      * @param length the number of elements to include
106      * @return the sum of the values or Double.NaN if length = 0
107      * @throws MathIllegalArgumentException if the array is null or the array index
108      *  parameters are not valid
109      */
110     public static double sum(final double[] values, final int begin, final int length)
111         throws MathIllegalArgumentException {
112         return SUM.evaluate(values, begin, length);
113     }
114 
115     /**
116      * Returns the sum of the squares of the entries in the input array, or
117      * <code>Double.NaN</code> if the array is empty.
118      * <p>
119      * Throws <code>IllegalArgumentException</code> if the array is null.
120      *
121      * @param values  input array
122      * @return the sum of the squared values or <code>Double.NaN</code> if the array is empty
123      * @throws MathIllegalArgumentException if the array is null
124      */
125     public static double sumSq(final double[] values) throws MathIllegalArgumentException {
126         return SUM_OF_SQUARES.evaluate(values);
127     }
128 
129     /**
130      * Returns the sum of the squares of the entries in the specified portion of
131      * the input array, or <code>Double.NaN</code> if the designated subarray
132      * is empty.
133      * <p>
134      * Throws <code>IllegalArgumentException</code> if the array is null.
135      *
136      * @param values the input array
137      * @param begin index of the first array element to include
138      * @param length the number of elements to include
139      * @return the sum of the squares of the values or Double.NaN if length = 0
140      * @throws MathIllegalArgumentException if the array is null or the array index
141      *  parameters are not valid
142      */
143     public static double sumSq(final double[] values, final int begin, final int length)
144         throws MathIllegalArgumentException {
145         return SUM_OF_SQUARES.evaluate(values, begin, length);
146     }
147 
148     /**
149      * Returns the product of the entries in the input array, or
150      * <code>Double.NaN</code> if the array is empty.
151      * <p>
152      * Throws <code>IllegalArgumentException</code> if the array is null.
153      *
154      * @param values the input array
155      * @return the product of the values or Double.NaN if the array is empty
156      * @throws MathIllegalArgumentException if the array is null
157      */
158     public static double product(final double[] values) throws MathIllegalArgumentException {
159         return PRODUCT.evaluate(values);
160     }
161 
162     /**
163      * Returns the product of the entries in the specified portion of
164      * the input array, or <code>Double.NaN</code> if the designated subarray
165      * is empty.
166      * <p>
167      * Throws <code>IllegalArgumentException</code> if the array is null.
168      *
169      * @param values the input array
170      * @param begin index of the first array element to include
171      * @param length the number of elements to include
172      * @return the product of the values or Double.NaN if length = 0
173      * @throws MathIllegalArgumentException if the array is null or the array index
174      *  parameters are not valid
175      */
176     public static double product(final double[] values, final int begin, final int length)
177         throws MathIllegalArgumentException {
178         return PRODUCT.evaluate(values, begin, length);
179     }
180 
181     /**
182      * Returns the sum of the natural logs of the entries in the input array, or
183      * <code>Double.NaN</code> if the array is empty.
184      * <p>
185      * Throws <code>IllegalArgumentException</code> if the array is null.
186      * <p>
187      * See {@link org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs}.
188      *
189      * @param values the input array
190      * @return the sum of the natural logs of the values or Double.NaN if the array is empty
191      * @throws MathIllegalArgumentException if the array is null
192      */
193     public static double sumLog(final double[] values) throws MathIllegalArgumentException {
194         return SUM_OF_LOGS.evaluate(values);
195     }
196 
197     /**
198      * Returns the sum of the natural logs of the entries in the specified portion of
199      * the input array, or <code>Double.NaN</code> if the designated subarray is empty.
200      * <p>
201      * Throws <code>IllegalArgumentException</code> if the array is null.
202      * <p>
203      * See {@link org.apache.commons.math4.legacy.stat.descriptive.summary.SumOfLogs}.
204      *
205      * @param values the input array
206      * @param begin index of the first array element to include
207      * @param length the number of elements to include
208      * @return the sum of the natural logs of the values or Double.NaN if
209      * length = 0
210      * @throws MathIllegalArgumentException if the array is null or the array index
211      * parameters are not valid
212      */
213     public static double sumLog(final double[] values, final int begin, final int length)
214         throws MathIllegalArgumentException {
215         return SUM_OF_LOGS.evaluate(values, begin, length);
216     }
217 
218     /**
219      * Returns the arithmetic mean of the entries in the input array, or
220      * <code>Double.NaN</code> if the array is empty.
221      * <p>
222      * Throws <code>IllegalArgumentException</code> if the array is null.
223      * <p>
224      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Mean} for
225      * details on the computing algorithm.
226      *
227      * @param values the input array
228      * @return the mean of the values or Double.NaN if the array is empty
229      * @throws MathIllegalArgumentException if the array is null
230      */
231     public static double mean(final double[] values) throws MathIllegalArgumentException {
232         return MEAN.evaluate(values);
233     }
234 
235     /**
236      * Returns the arithmetic mean of the entries in the specified portion of
237      * the input array, or <code>Double.NaN</code> if the designated subarray
238      * is empty.
239      * <p>
240      * Throws <code>IllegalArgumentException</code> if the array is null.
241      * <p>
242      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Mean Mean} for
243      * details on the computing algorithm.
244      *
245      * @param values the input array
246      * @param begin index of the first array element to include
247      * @param length the number of elements to include
248      * @return the mean of the values or Double.NaN if length = 0
249      * @throws MathIllegalArgumentException if the array is null or the array index
250      * parameters are not valid
251      */
252     public static double mean(final double[] values, final int begin, final int length)
253         throws MathIllegalArgumentException {
254         return MEAN.evaluate(values, begin, length);
255     }
256 
257     /**
258      * Returns the geometric mean of the entries in the input array, or
259      * <code>Double.NaN</code> if the array is empty.
260      * <p>
261      * Throws <code>IllegalArgumentException</code> if the array is null.
262      * <p>
263      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean GeometricMean}
264      * for details on the computing algorithm.
265      *
266      * @param values the input array
267      * @return the geometric mean of the values or Double.NaN if the array is empty
268      * @throws MathIllegalArgumentException if the array is null
269      */
270     public static double geometricMean(final double[] values) throws MathIllegalArgumentException {
271         return GEOMETRIC_MEAN.evaluate(values);
272     }
273 
274     /**
275      * Returns the geometric mean of the entries in the specified portion of
276      * the input array, or <code>Double.NaN</code> if the designated subarray
277      * is empty.
278      * <p>
279      * Throws <code>IllegalArgumentException</code> if the array is null.
280      * <p>
281      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.GeometricMean GeometricMean}
282      * for details on the computing algorithm.
283      *
284      * @param values the input array
285      * @param begin index of the first array element to include
286      * @param length the number of elements to include
287      * @return the geometric mean of the values or Double.NaN if length = 0
288      * @throws MathIllegalArgumentException if the array is null or the array index
289      *  parameters are not valid
290      */
291     public static double geometricMean(final double[] values, final int begin, final int length)
292         throws MathIllegalArgumentException {
293         return GEOMETRIC_MEAN.evaluate(values, begin, length);
294     }
295 
296     /**
297      * Returns the variance of the entries in the input array, or
298      * <code>Double.NaN</code> if the array is empty.
299      * <p>
300      * This method returns the bias-corrected sample variance (using {@code n - 1} in
301      * the denominator). Use {@link #populationVariance(double[])} for the non-bias-corrected
302      * population variance.
303      * <p>
304      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
305      * details on the computing algorithm.
306      * <p>
307      * Returns 0 for a single-value (i.e. length = 1) sample.
308      * <p>
309      * Throws <code>MathIllegalArgumentException</code> if the array is null.
310      *
311      * @param values the input array
312      * @return the variance of the values or Double.NaN if the array is empty
313      * @throws MathIllegalArgumentException if the array is null
314      */
315     public static double variance(final double[] values) throws MathIllegalArgumentException {
316         return VARIANCE.evaluate(values);
317     }
318 
319     /**
320      * Returns the variance of the entries in the specified portion of
321      * the input array, or <code>Double.NaN</code> if the designated subarray
322      * is empty.
323      * <p>
324      * This method returns the bias-corrected sample variance (using {@code n - 1} in
325      * the denominator). Use {@link #populationVariance(double[], int, int)} for the non-bias-corrected
326      * population variance.
327      * <p>
328      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
329      * details on the computing algorithm.
330      * <p>
331      * Returns 0 for a single-value (i.e. length = 1) sample.
332      * <p>
333      * Throws <code>MathIllegalArgumentException</code> if the array is null or the
334      * array index parameters are not valid.
335      *
336      * @param values the input array
337      * @param begin index of the first array element to include
338      * @param length the number of elements to include
339      * @return the variance of the values or Double.NaN if length = 0
340      * @throws MathIllegalArgumentException if the array is null or the array index
341      *  parameters are not valid
342      */
343     public static double variance(final double[] values, final int begin, final int length)
344         throws MathIllegalArgumentException {
345         return VARIANCE.evaluate(values, begin, length);
346     }
347 
348     /**
349      * Returns the variance of the entries in the specified portion of
350      * the input array, using the precomputed mean value.  Returns
351      * <code>Double.NaN</code> if the designated subarray is empty.
352      * <p>
353      * This method returns the bias-corrected sample variance (using {@code n - 1} in
354      * the denominator). Use {@link #populationVariance(double[], double, int, int)} for
355      * the non-bias-corrected population variance.
356      * <p>
357      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
358      * details on the computing algorithm.
359      * <p>
360      * The formula used assumes that the supplied mean value is the arithmetic
361      * mean of the sample data, not a known population parameter.  This method
362      * is supplied only to save computation when the mean has already been
363      * computed.
364      * <p>
365      * Returns 0 for a single-value (i.e. length = 1) sample.
366      * <p>
367      * Throws <code>MathIllegalArgumentException</code> if the array is null or the
368      * array index parameters are not valid.
369      *
370      * @param values the input array
371      * @param mean the precomputed mean value
372      * @param begin index of the first array element to include
373      * @param length the number of elements to include
374      * @return the variance of the values or Double.NaN if length = 0
375      * @throws MathIllegalArgumentException if the array is null or the array index
376      *  parameters are not valid
377      */
378     public static double variance(final double[] values, final double mean, final int begin, final int length)
379         throws MathIllegalArgumentException {
380         return VARIANCE.evaluate(values, mean, begin, length);
381     }
382 
383     /**
384      * Returns the variance of the entries in the input array, using the
385      * precomputed mean value.  Returns <code>Double.NaN</code> if the array
386      * is empty.
387      * <p>
388      * This method returns the bias-corrected sample variance (using {@code n - 1} in
389      * the denominator).  Use {@link #populationVariance(double[], double)} for the
390      * non-bias-corrected population variance.
391      * <p>
392      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
393      * details on the computing algorithm.
394      * <p>
395      * The formula used assumes that the supplied mean value is the arithmetic
396      * mean of the sample data, not a known population parameter.  This method
397      * is supplied only to save computation when the mean has already been
398      * computed.
399      * <p>
400      * Returns 0 for a single-value (i.e. length = 1) sample.
401      * <p>
402      * Throws <code>MathIllegalArgumentException</code> if the array is null.
403      *
404      * @param values the input array
405      * @param mean the precomputed mean value
406      * @return the variance of the values or Double.NaN if the array is empty
407      * @throws MathIllegalArgumentException if the array is null
408      */
409     public static double variance(final double[] values, final double mean) throws MathIllegalArgumentException {
410         return VARIANCE.evaluate(values, mean);
411     }
412 
413     /**
414      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
415      * population variance</a> of the entries in the input array, or
416      * <code>Double.NaN</code> if the array is empty.
417      * <p>
418      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
419      * details on the formula and computing algorithm.
420      * <p>
421      * Returns 0 for a single-value (i.e. length = 1) sample.
422      * <p>
423      * Throws <code>MathIllegalArgumentException</code> if the array is null.
424      *
425      * @param values the input array
426      * @return the population variance of the values or Double.NaN if the array is empty
427      * @throws MathIllegalArgumentException if the array is null
428      */
429     public static double populationVariance(final double[] values) throws MathIllegalArgumentException {
430         return new Variance(false).evaluate(values);
431     }
432 
433     /**
434      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
435      * population variance</a> of the entries in the specified portion of
436      * the input array, or <code>Double.NaN</code> if the designated subarray
437      * is empty.
438      * <p>
439      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
440      * details on the computing algorithm.
441      * <p>
442      * Returns 0 for a single-value (i.e. length = 1) sample.
443      * <p>
444      * Throws <code>MathIllegalArgumentException</code> if the array is null or the
445      * array index parameters are not valid.
446      *
447      * @param values the input array
448      * @param begin index of the first array element to include
449      * @param length the number of elements to include
450      * @return the population variance of the values or Double.NaN if length = 0
451      * @throws MathIllegalArgumentException if the array is null or the array index
452      *  parameters are not valid
453      */
454     public static double populationVariance(final double[] values, final int begin, final int length)
455         throws MathIllegalArgumentException {
456         return new Variance(false).evaluate(values, begin, length);
457     }
458 
459     /**
460      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
461      * population variance</a> of the entries in the specified portion of
462      * the input array, using the precomputed mean value.  Returns
463      * <code>Double.NaN</code> if the designated subarray is empty.
464      * <p>
465      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
466      * details on the computing algorithm.
467      * <p>
468      * The formula used assumes that the supplied mean value is the arithmetic
469      * mean of the sample data, not a known population parameter.  This method
470      * is supplied only to save computation when the mean has already been
471      * computed.
472      * <p>
473      * Returns 0 for a single-value (i.e. length = 1) sample.
474      * <p>
475      * Throws <code>MathIllegalArgumentException</code> if the array is null or the
476      * array index parameters are not valid.
477      *
478      * @param values the input array
479      * @param mean the precomputed mean value
480      * @param begin index of the first array element to include
481      * @param length the number of elements to include
482      * @return the population variance of the values or Double.NaN if length = 0
483      * @throws MathIllegalArgumentException if the array is null or the array index
484      *  parameters are not valid
485      */
486     public static double populationVariance(final double[] values, final double mean,
487                                             final int begin, final int length)
488         throws MathIllegalArgumentException {
489         return new Variance(false).evaluate(values, mean, begin, length);
490     }
491 
492     /**
493      * Returns the <a href="http://en.wikibooks.org/wiki/Statistics/Summary/Variance">
494      * population variance</a> of the entries in the input array, using the precomputed
495      * mean value. Returns <code>Double.NaN</code> if the array is empty.
496      * <p>
497      * See {@link org.apache.commons.math4.legacy.stat.descriptive.moment.Variance Variance} for
498      * details on the computing algorithm.
499      * <p>
500      * The formula used assumes that the supplied mean value is the arithmetic
501      * mean of the sample data, not a known population parameter. This method is
502      * supplied only to save computation when the mean has already been computed.
503      * <p>
504      * Returns 0 for a single-value (i.e. length = 1) sample.
505      * <p>
506      * Throws <code>MathIllegalArgumentException</code> if the array is null.
507      *
508      * @param values the input array
509      * @param mean the precomputed mean value
510      * @return the population variance of the values or Double.NaN if the array is empty
511      * @throws MathIllegalArgumentException if the array is null
512      */
513     public static double populationVariance(final double[] values, final double mean)
514         throws MathIllegalArgumentException {
515         return new Variance(false).evaluate(values, mean);
516     }
517 
518     /**
519      * Returns the maximum of the entries in the input array, or
520      * <code>Double.NaN</code> if the array is empty.
521      * <p>
522      * Throws <code>MathIllegalArgumentException</code> if the array is null.
523      * <ul>
524      * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
525      * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
526      * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
527      * the result is <code>Double.POSITIVE_INFINITY.</code></li>
528      * </ul>
529      *
530      * @param values the input array
531      * @return the maximum of the values or Double.NaN if the array is empty
532      * @throws MathIllegalArgumentException if the array is null
533      */
534     public static double max(final double[] values) throws MathIllegalArgumentException {
535         return MAX.evaluate(values);
536     }
537 
538     /**
539      * Returns the maximum of the entries in the specified portion of the input array,
540      * or <code>Double.NaN</code> if the designated subarray is empty.
541      * <p>
542      * Throws <code>MathIllegalArgumentException</code> if the array is null or
543      * the array index parameters are not valid.
544      * <ul>
545      * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
546      * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
547      * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
548      * the result is <code>Double.POSITIVE_INFINITY.</code></li>
549      * </ul>
550      *
551      * @param values the input array
552      * @param begin index of the first array element to include
553      * @param length the number of elements to include
554      * @return the maximum of the values or Double.NaN if length = 0
555      * @throws MathIllegalArgumentException if the array is null or the array index
556      *  parameters are not valid
557      */
558     public static double max(final double[] values, final int begin, final int length)
559         throws MathIllegalArgumentException {
560         return MAX.evaluate(values, begin, length);
561     }
562 
563     /**
564      * Returns the minimum of the entries in the input array, or
565      * <code>Double.NaN</code> if the array is empty.
566      * <p>
567      * Throws <code>MathIllegalArgumentException</code> if the array is null.
568      * <ul>
569      * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
570      * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
571      * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
572      * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
573      * </ul>
574      *
575      * @param values the input array
576      * @return the minimum of the values or Double.NaN if the array is empty
577      * @throws MathIllegalArgumentException if the array is null
578      */
579     public static double min(final double[] values) throws MathIllegalArgumentException {
580         return MIN.evaluate(values);
581     }
582 
583     /**
584      * Returns the minimum of the entries in the specified portion of the input array,
585      * or <code>Double.NaN</code> if the designated subarray is empty.
586      * <p>
587      * Throws <code>MathIllegalArgumentException</code> if the array is null or
588      * the array index parameters are not valid.
589      * <ul>
590      * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
591      * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
592      * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
593      * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
594      * </ul>
595      *
596      * @param values the input array
597      * @param begin index of the first array element to include
598      * @param length the number of elements to include
599      * @return the minimum of the values or Double.NaN if length = 0
600      * @throws MathIllegalArgumentException if the array is null or the array index
601      *  parameters are not valid
602      */
603     public static double min(final double[] values, final int begin, final int length)
604         throws MathIllegalArgumentException {
605         return MIN.evaluate(values, begin, length);
606     }
607 
608     /**
609      * Returns an estimate of the <code>p</code>th percentile of the values
610      * in the <code>values</code> array.
611      * <ul>
612      * <li>Returns <code>Double.NaN</code> if <code>values</code> has length
613      *  <code>0</code></li>
614      * <li>Returns (for any value of <code>p</code>) <code>values[0]</code>
615      *  if <code>values</code> has length <code>1</code></li>
616      * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
617      *  is null  or p is not a valid quantile value (p must be greater than 0
618      *  and less than or equal to 100)</li>
619      * </ul>
620      * <p>
621      * See {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile Percentile}
622      * for a description of the percentile estimation algorithm used.
623      *
624      * @param values input array of values
625      * @param p the percentile value to compute
626      * @return the percentile value or Double.NaN if the array is empty
627      * @throws MathIllegalArgumentException if <code>values</code> is null or p is invalid
628      */
629     public static double percentile(final double[] values, final double p) throws MathIllegalArgumentException {
630         return PERCENTILE.evaluate(values,p);
631     }
632 
633     /**
634      * Returns an estimate of the <code>p</code>th percentile of the values
635      * in the <code>values</code> array, starting with the element in (0-based)
636      * position <code>begin</code> in the array and including <code>length</code>
637      * values.
638      * <ul>
639      * <li>Returns <code>Double.NaN</code> if <code>length = 0</code></li>
640      * <li>Returns (for any value of <code>p</code>) <code>values[begin]</code>
641      *  if <code>length = 1 </code></li>
642      * <li>Throws <code>MathIllegalArgumentException</code> if <code>values</code>
643      *  is null, <code>begin</code> or <code>length</code> is invalid, or
644      *  <code>p</code> is not a valid quantile value (p must be greater than 0
645      *  and less than or equal to 100)</li>
646      * </ul>
647      * <p>
648      * See {@link org.apache.commons.math4.legacy.stat.descriptive.rank.Percentile Percentile}
649      * for a description of the percentile estimation algorithm used.
650      *
651      * @param values array of input values
652      * @param p the percentile to compute
653      * @param begin the first (0-based) element to include in the computation
654      * @param length the number of array elements to include
655      * @return the percentile value
656      * @throws MathIllegalArgumentException if the parameters are not valid or the input array is null
657      */
658     public static double percentile(final double[] values, final int begin, final int length, final double p)
659         throws MathIllegalArgumentException {
660         return PERCENTILE.evaluate(values, begin, length, p);
661     }
662 
663     /**
664      * Returns the sum of the (signed) differences between corresponding elements of the
665      * input arrays -- i.e., sum(sample1[i] - sample2[i]).
666      *
667      * @param sample1  the first array
668      * @param sample2  the second array
669      * @return sum of paired differences
670      * @throws DimensionMismatchException if the arrays do not have the same (positive) length.
671      * @throws NoDataException if the sample arrays are empty.
672      */
673     public static double sumDifference(final double[] sample1, final double[] sample2)
674         throws DimensionMismatchException, NoDataException {
675 
676         int n = sample1.length;
677         if (n != sample2.length) {
678             throw new DimensionMismatchException(n, sample2.length);
679         }
680         if (n <= 0) {
681             throw new NoDataException(LocalizedFormats.INSUFFICIENT_DIMENSION);
682         }
683         double result = 0;
684         for (int i = 0; i < n; i++) {
685             result += sample1[i] - sample2[i];
686         }
687         return result;
688     }
689 
690     /**
691      * Returns the mean of the (signed) differences between corresponding elements of the
692      * input arrays -- i.e., sum(sample1[i] - sample2[i]) / sample1.length.
693      *
694      * @param sample1  the first array
695      * @param sample2  the second array
696      * @return mean of paired differences
697      * @throws DimensionMismatchException if the arrays do not have the same (positive) length.
698      * @throws NoDataException if the sample arrays are empty.
699      */
700     public static double meanDifference(final double[] sample1, final double[] sample2)
701         throws DimensionMismatchException, NoDataException {
702         return sumDifference(sample1, sample2) / sample1.length;
703     }
704 
705     /**
706      * Returns the variance of the (signed) differences between corresponding elements of the
707      * input arrays -- i.e., var(sample1[i] - sample2[i]).
708      *
709      * @param sample1  the first array
710      * @param sample2  the second array
711      * @param meanDifference   the mean difference between corresponding entries
712      * @return variance of paired differences
713      * @throws DimensionMismatchException if the arrays do not have the same length.
714      * @throws NumberIsTooSmallException if the arrays length is less than 2.
715      * @see #meanDifference(double[],double[])
716      */
717     public static double varianceDifference(final double[] sample1, final double[] sample2, double meanDifference)
718         throws DimensionMismatchException, NumberIsTooSmallException {
719 
720         double sum1 = 0d;
721         double sum2 = 0d;
722         double diff = 0d;
723         int n = sample1.length;
724         if (n != sample2.length) {
725             throw new DimensionMismatchException(n, sample2.length);
726         }
727         if (n < 2) {
728             throw new NumberIsTooSmallException(n, 2, true);
729         }
730         for (int i = 0; i < n; i++) {
731             diff = sample1[i] - sample2[i];
732             sum1 += (diff - meanDifference) *(diff - meanDifference);
733             sum2 += diff - meanDifference;
734         }
735         return (sum1 - (sum2 * sum2 / n)) / (n - 1);
736     }
737 
738     /**
739      * Normalize (standardize) the sample, so it is has a mean of 0 and a standard deviation of 1.
740      *
741      * @param sample Sample to normalize.
742      * @return normalized (standardized) sample.
743      * @since 2.2
744      */
745     public static double[] normalize(final double[] sample) {
746         DescriptiveStatistics stats = new DescriptiveStatistics();
747 
748         // Add the data from the series to stats
749         for (int i = 0; i < sample.length; i++) {
750             stats.addValue(sample[i]);
751         }
752 
753         // Compute mean and standard deviation
754         double mean = stats.getMean();
755         double standardDeviation = stats.getStandardDeviation();
756 
757         // initialize the standardizedSample, which has the same length as the sample
758         double[] standardizedSample = new double[sample.length];
759 
760         for (int i = 0; i < sample.length; i++) {
761             // z = (x- mean)/standardDeviation
762             standardizedSample[i] = (sample[i] - mean) / standardDeviation;
763         }
764         return standardizedSample;
765     }
766 
767     /**
768      * Returns the sample mode(s).
769      * <p>
770      * The mode is the most frequently occurring value in the sample.
771      * If there is a unique value with maximum frequency, this value is returned
772      * as the only element of the output array. Otherwise, the returned array
773      * contains the maximum frequency elements in increasing order.
774      * <p>
775      * For example, if {@code sample} is {0, 12, 5, 6, 0, 13, 5, 17},
776      * the returned array will have length two, with 0 in the first element and
777      * 5 in the second.
778      * <p>
779      * NaN values are ignored when computing the mode - i.e., NaNs will never
780      * appear in the output array.  If the sample includes only NaNs or has
781      * length 0, an empty array is returned.
782      *
783      * @param sample input data
784      * @return array of array of the most frequently occurring element(s) sorted in ascending order.
785      * @throws MathIllegalArgumentException if the indices are invalid or the array is null
786      * @since 3.3
787      */
788     public static double[] mode(double[] sample) throws MathIllegalArgumentException {
789         if (sample == null) {
790             throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
791         }
792         return getMode(sample, 0, sample.length);
793     }
794 
795     /**
796      * Returns the sample mode(s).
797      * <p>
798      * The mode is the most frequently occurring value in the sample.
799      * If there is a unique value with maximum frequency, this value is returned
800      * as the only element of the output array. Otherwise, the returned array
801      * contains the maximum frequency elements in increasing order.
802      * <p>
803      * For example, if {@code sample} is {0, 12, 5, 6, 0, 13, 5, 17},
804      * the returned array will have length two, with 0 in the first element and
805      * 5 in the second.
806      * <p>
807      * NaN values are ignored when computing the mode - i.e., NaNs will never
808      * appear in the output array.  If the sample includes only NaNs or has
809      * length 0, an empty array is returned.
810      *
811      * @param sample input data
812      * @param begin index (0-based) of the first array element to include
813      * @param length the number of elements to include
814      * @return array of array of the most frequently occurring element(s) sorted in ascending order.
815      * @throws MathIllegalArgumentException if the indices are invalid or the array is null
816      * @since 3.3
817      */
818     public static double[] mode(double[] sample, final int begin, final int length) {
819         if (sample == null) {
820             throw new NullArgumentException(LocalizedFormats.INPUT_ARRAY);
821         }
822 
823         if (begin < 0) {
824             throw new NotPositiveException(LocalizedFormats.START_POSITION, Integer.valueOf(begin));
825         }
826 
827         if (length < 0) {
828             throw new NotPositiveException(LocalizedFormats.LENGTH, Integer.valueOf(length));
829         }
830 
831         return getMode(sample, begin, length);
832     }
833 
834     /**
835      * Private helper method.
836      * Assumes parameters have been validated.
837      * @param values input data
838      * @param begin index (0-based) of the first array element to include
839      * @param length the number of elements to include
840      * @return array of array of the most frequently occurring element(s) sorted in ascending order.
841      */
842     private static double[] getMode(double[] values, final int begin, final int length) {
843         // Add the values to the frequency table
844         Frequency<Double> freq = new Frequency<>();
845         for (int i = begin; i < begin + length; i++) {
846             final double value = values[i];
847             if (!Double.isNaN(value)) {
848                 freq.addValue(Double.valueOf(value));
849             }
850         }
851         List<Double> list = freq.getMode();
852         // Convert the list to an array of primitive double
853         return list.stream().mapToDouble(Double::doubleValue).toArray();
854     }
855 }