001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.commons.math.stat;
018    
019    import org.apache.commons.math.MathRuntimeException;
020    import org.apache.commons.math.exception.util.LocalizedFormats;
021    import org.apache.commons.math.stat.descriptive.DescriptiveStatistics;
022    import org.apache.commons.math.stat.descriptive.UnivariateStatistic;
023    import org.apache.commons.math.stat.descriptive.moment.GeometricMean;
024    import org.apache.commons.math.stat.descriptive.moment.Mean;
025    import org.apache.commons.math.stat.descriptive.moment.Variance;
026    import org.apache.commons.math.stat.descriptive.rank.Max;
027    import org.apache.commons.math.stat.descriptive.rank.Min;
028    import org.apache.commons.math.stat.descriptive.rank.Percentile;
029    import org.apache.commons.math.stat.descriptive.summary.Product;
030    import org.apache.commons.math.stat.descriptive.summary.Sum;
031    import org.apache.commons.math.stat.descriptive.summary.SumOfLogs;
032    import org.apache.commons.math.stat.descriptive.summary.SumOfSquares;
033    
034    /**
035     * StatUtils provides static methods for computing statistics based on data
036     * stored in double[] arrays.
037     *
038     * @version $Revision: 1073276 $ $Date: 2011-02-22 10:34:52 +0100 (mar. 22 f??vr. 2011) $
039     */
040    public final class StatUtils {
041    
042        /** sum */
043        private static final UnivariateStatistic SUM = new Sum();
044    
045        /** sumSq */
046        private static final UnivariateStatistic SUM_OF_SQUARES = new SumOfSquares();
047    
048        /** prod */
049        private static final UnivariateStatistic PRODUCT = new Product();
050    
051        /** sumLog */
052        private static final UnivariateStatistic SUM_OF_LOGS = new SumOfLogs();
053    
054        /** min */
055        private static final UnivariateStatistic MIN = new Min();
056    
057        /** max */
058        private static final UnivariateStatistic MAX = new Max();
059    
060        /** mean */
061        private static final UnivariateStatistic MEAN = new Mean();
062    
063        /** variance */
064        private static final Variance VARIANCE = new Variance();
065    
066        /** percentile */
067        private static final Percentile PERCENTILE = new Percentile();
068    
069        /** geometric mean */
070        private static final GeometricMean GEOMETRIC_MEAN = new GeometricMean();
071    
072        /**
073         * Private Constructor
074         */
075        private StatUtils() {
076        }
077    
078        /**
079         * Returns the sum of the values in the input array, or
080         * <code>Double.NaN</code> if the array is empty.
081         * <p>
082         * Throws <code>IllegalArgumentException</code> if the input array
083         * is null.</p>
084         *
085         * @param values  array of values to sum
086         * @return the sum of the values or <code>Double.NaN</code> if the array
087         * is empty
088         * @throws IllegalArgumentException if the array is null
089         */
090        public static double sum(final double[] values) {
091            return SUM.evaluate(values);
092        }
093    
094        /**
095         * Returns the sum of the entries in the specified portion of
096         * the input array, or <code>Double.NaN</code> if the designated subarray
097         * is empty.
098         * <p>
099         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
100         *
101         * @param values the input array
102         * @param begin index of the first array element to include
103         * @param length the number of elements to include
104         * @return the sum of the values or Double.NaN if length = 0
105         * @throws IllegalArgumentException if the array is null or the array index
106         *  parameters are not valid
107         */
108        public static double sum(final double[] values, final int begin,
109                final int length) {
110            return SUM.evaluate(values, begin, length);
111        }
112    
113        /**
114         * Returns the sum of the squares of the entries in the input array, or
115         * <code>Double.NaN</code> if the array is empty.
116         * <p>
117         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
118         *
119         * @param values  input array
120         * @return the sum of the squared values or <code>Double.NaN</code> if the
121         * array is empty
122         * @throws IllegalArgumentException if the array is null
123         */
124        public static double sumSq(final double[] values) {
125            return SUM_OF_SQUARES.evaluate(values);
126        }
127    
128        /**
129         * Returns the sum of the squares of the entries in the specified portion of
130         * the input array, or <code>Double.NaN</code> if the designated subarray
131         * is empty.
132         * <p>
133         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
134         *
135         * @param values the input array
136         * @param begin index of the first array element to include
137         * @param length the number of elements to include
138         * @return the sum of the squares of the values or Double.NaN if length = 0
139         * @throws IllegalArgumentException if the array is null or the array index
140         * parameters are not valid
141         */
142        public static double sumSq(final double[] values, final int begin,
143                final int length) {
144            return SUM_OF_SQUARES.evaluate(values, begin, length);
145        }
146    
147        /**
148         * Returns the product of the entries in the input array, or
149         * <code>Double.NaN</code> if the array is empty.
150         * <p>
151         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
152         *
153         * @param values the input array
154         * @return the product of the values or Double.NaN if the array is empty
155         * @throws IllegalArgumentException if the array is null
156         */
157        public static double product(final double[] values) {
158            return PRODUCT.evaluate(values);
159        }
160    
161        /**
162         * Returns the product of the entries in the specified portion of
163         * the input array, or <code>Double.NaN</code> if the designated subarray
164         * is empty.
165         * <p>
166         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
167         *
168         * @param values the input array
169         * @param begin index of the first array element to include
170         * @param length the number of elements to include
171         * @return the product of the values or Double.NaN if length = 0
172         * @throws IllegalArgumentException if the array is null or the array index
173         * parameters are not valid
174         */
175        public static double product(final double[] values, final int begin,
176                final int length) {
177            return PRODUCT.evaluate(values, begin, length);
178        }
179    
180        /**
181         * Returns the sum of the natural logs of the entries in the input array, or
182         * <code>Double.NaN</code> if the array is empty.
183         * <p>
184         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
185         * <p>
186         * See {@link org.apache.commons.math.stat.descriptive.summary.SumOfLogs}.
187         * </p>
188         *
189         * @param values the input array
190         * @return the sum of the natural logs of the values or Double.NaN if
191         * the array is empty
192         * @throws IllegalArgumentException if the array is null
193         */
194        public static double sumLog(final double[] values) {
195            return SUM_OF_LOGS.evaluate(values);
196        }
197    
198        /**
199         * Returns the sum of the natural logs of the entries in the specified portion of
200         * the input array, or <code>Double.NaN</code> if the designated subarray
201         * is empty.
202         * <p>
203         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
204         * <p>
205         * See {@link org.apache.commons.math.stat.descriptive.summary.SumOfLogs}.
206         * </p>
207         *
208         * @param values the input array
209         * @param begin index of the first array element to include
210         * @param length the number of elements to include
211         * @return the sum of the natural logs of the values or Double.NaN if
212         * length = 0
213         * @throws IllegalArgumentException if the array is null or the array index
214         * parameters are not valid
215         */
216        public static double sumLog(final double[] values, final int begin,
217                final int length) {
218            return SUM_OF_LOGS.evaluate(values, begin, length);
219        }
220    
221        /**
222         * Returns the arithmetic mean of the entries in the input array, or
223         * <code>Double.NaN</code> if the array is empty.
224         * <p>
225         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
226         * <p>
227         * See {@link org.apache.commons.math.stat.descriptive.moment.Mean} for
228         * details on the computing algorithm.</p>
229         *
230         * @param values the input array
231         * @return the mean of the values or Double.NaN if the array is empty
232         * @throws IllegalArgumentException if the array is null
233         */
234        public static double mean(final double[] values) {
235            return MEAN.evaluate(values);
236        }
237    
238        /**
239         * Returns the arithmetic mean of the entries in the specified portion of
240         * the input array, or <code>Double.NaN</code> if the designated subarray
241         * is empty.
242         * <p>
243         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
244         * <p>
245         * See {@link org.apache.commons.math.stat.descriptive.moment.Mean} for
246         * details on the computing algorithm.</p>
247         *
248         * @param values the input array
249         * @param begin index of the first array element to include
250         * @param length the number of elements to include
251         * @return the mean of the values or Double.NaN if length = 0
252         * @throws IllegalArgumentException if the array is null or the array index
253         * parameters are not valid
254         */
255        public static double mean(final double[] values, final int begin,
256                final int length) {
257            return MEAN.evaluate(values, begin, length);
258        }
259    
260        /**
261         * Returns the geometric mean of the entries in the input array, or
262         * <code>Double.NaN</code> if the array is empty.
263         * <p>
264         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
265         * <p>
266         * See {@link org.apache.commons.math.stat.descriptive.moment.GeometricMean}
267         * for details on the computing algorithm.</p>
268         *
269         * @param values the input array
270         * @return the geometric mean of the values or Double.NaN if the array is empty
271         * @throws IllegalArgumentException if the array is null
272         */
273        public static double geometricMean(final double[] values) {
274            return GEOMETRIC_MEAN.evaluate(values);
275        }
276    
277        /**
278         * Returns the geometric mean of the entries in the specified portion of
279         * the input array, or <code>Double.NaN</code> if the designated subarray
280         * is empty.
281         * <p>
282         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
283         * <p>
284         * See {@link org.apache.commons.math.stat.descriptive.moment.GeometricMean}
285         * for details on the computing algorithm.</p>
286         *
287         * @param values the input array
288         * @param begin index of the first array element to include
289         * @param length the number of elements to include
290         * @return the geometric mean of the values or Double.NaN if length = 0
291         * @throws IllegalArgumentException if the array is null or the array index
292         * parameters are not valid
293         */
294        public static double geometricMean(final double[] values, final int begin,
295                final int length) {
296            return GEOMETRIC_MEAN.evaluate(values, begin, length);
297        }
298    
299    
300        /**
301         * Returns the variance of the entries in the input array, or
302         * <code>Double.NaN</code> if the array is empty.
303         * <p>
304         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
305         * details on the computing algorithm.</p>
306         * <p>
307         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
308         * <p>
309         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
310         *
311         * @param values the input array
312         * @return the variance of the values or Double.NaN if the array is empty
313         * @throws IllegalArgumentException if the array is null
314         */
315        public static double variance(final double[] values) {
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         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
325         * details on the computing algorithm.</p>
326         * <p>
327         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
328         * <p>
329         * Throws <code>IllegalArgumentException</code> if the array is null or the
330         * array index parameters are not valid.</p>
331         *
332         * @param values the input array
333         * @param begin index of the first array element to include
334         * @param length the number of elements to include
335         * @return the variance of the values or Double.NaN if length = 0
336         * @throws IllegalArgumentException if the array is null or the array index
337         *  parameters are not valid
338         */
339        public static double variance(final double[] values, final int begin,
340                final int length) {
341            return VARIANCE.evaluate(values, begin, length);
342        }
343    
344        /**
345         * Returns the variance of the entries in the specified portion of
346         * the input array, using the precomputed mean value.  Returns
347         * <code>Double.NaN</code> if the designated subarray is empty.
348         * <p>
349         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
350         * details on the computing algorithm.</p>
351         * <p>
352         * The formula used assumes that the supplied mean value is the arithmetic
353         * mean of the sample data, not a known population parameter.  This method
354         * is supplied only to save computation when the mean has already been
355         * computed.</p>
356         * <p>
357         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
358         * <p>
359         * Throws <code>IllegalArgumentException</code> if the array is null or the
360         * array index parameters are not valid.</p>
361         *
362         * @param values the input array
363         * @param mean the precomputed mean value
364         * @param begin index of the first array element to include
365         * @param length the number of elements to include
366         * @return the variance of the values or Double.NaN if length = 0
367         * @throws IllegalArgumentException if the array is null or the array index
368         *  parameters are not valid
369         */
370        public static double variance(final double[] values, final double mean,
371                final int begin, final int length) {
372            return VARIANCE.evaluate(values, mean, begin, length);
373        }
374    
375        /**
376         * Returns the variance of the entries in the input array, using the
377         * precomputed mean value.  Returns <code>Double.NaN</code> if the array
378         * is empty.
379         * <p>
380         * See {@link org.apache.commons.math.stat.descriptive.moment.Variance} for
381         * details on the computing algorithm.</p>
382         * <p>
383         * The formula used assumes that the supplied mean value is the arithmetic
384         * mean of the sample data, not a known population parameter.  This method
385         * is supplied only to save computation when the mean has already been
386         * computed.</p>
387         * <p>
388         * Returns 0 for a single-value (i.e. length = 1) sample.</p>
389         * <p>
390         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
391         *
392         * @param values the input array
393         * @param mean the precomputed mean value
394         * @return the variance of the values or Double.NaN if the array is empty
395         * @throws IllegalArgumentException if the array is null
396         */
397        public static double variance(final double[] values, final double mean) {
398            return VARIANCE.evaluate(values, mean);
399        }
400    
401        /**
402         * Returns the maximum of the entries in the input array, or
403         * <code>Double.NaN</code> if the array is empty.
404         * <p>
405         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
406         * <p>
407         * <ul>
408         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
409         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
410         * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
411         * the result is <code>Double.POSITIVE_INFINITY.</code></li>
412         * </ul></p>
413         *
414         * @param values the input array
415         * @return the maximum of the values or Double.NaN if the array is empty
416         * @throws IllegalArgumentException if the array is null
417         */
418        public static double max(final double[] values) {
419            return MAX.evaluate(values);
420        }
421    
422        /**
423         * Returns the maximum of the entries in the specified portion of
424         * the input array, or <code>Double.NaN</code> if the designated subarray
425         * is empty.
426         * <p>
427         * Throws <code>IllegalArgumentException</code> if the array is null or
428         * the array index parameters are not valid.</p>
429         * <p>
430         * <ul>
431         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
432         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
433         * <li>If any of the values equals <code>Double.POSITIVE_INFINITY</code>,
434         * the result is <code>Double.POSITIVE_INFINITY.</code></li>
435         * </ul></p>
436         *
437         * @param values the input array
438         * @param begin index of the first array element to include
439         * @param length the number of elements to include
440         * @return the maximum of the values or Double.NaN if length = 0
441         * @throws IllegalArgumentException if the array is null or the array index
442         * parameters are not valid
443         */
444        public static double max(final double[] values, final int begin,
445                final int length) {
446            return MAX.evaluate(values, begin, length);
447        }
448    
449         /**
450         * Returns the minimum of the entries in the input array, or
451         * <code>Double.NaN</code> if the array is empty.
452         * <p>
453         * Throws <code>IllegalArgumentException</code> if the array is null.</p>
454         * <p>
455         * <ul>
456         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
457         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
458         * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
459         * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
460         * </ul> </p>
461         *
462         * @param values the input array
463         * @return the minimum of the values or Double.NaN if the array is empty
464         * @throws IllegalArgumentException if the array is null
465         */
466        public static double min(final double[] values) {
467            return MIN.evaluate(values);
468        }
469    
470         /**
471         * Returns the minimum of the entries in the specified portion of
472         * the input array, or <code>Double.NaN</code> if the designated subarray
473         * is empty.
474         * <p>
475         * Throws <code>IllegalArgumentException</code> if the array is null or
476         * the array index parameters are not valid.</p>
477         * <p>
478         * <ul>
479         * <li>The result is <code>NaN</code> iff all values are <code>NaN</code>
480         * (i.e. <code>NaN</code> values have no impact on the value of the statistic).</li>
481         * <li>If any of the values equals <code>Double.NEGATIVE_INFINITY</code>,
482         * the result is <code>Double.NEGATIVE_INFINITY.</code></li>
483         * </ul></p>
484         *
485         * @param values the input array
486         * @param begin index of the first array element to include
487         * @param length the number of elements to include
488         * @return the minimum of the values or Double.NaN if length = 0
489         * @throws IllegalArgumentException if the array is null or the array index
490         * parameters are not valid
491         */
492        public static double min(final double[] values, final int begin,
493                final int length) {
494            return MIN.evaluate(values, begin, length);
495        }
496    
497        /**
498         * Returns an estimate of the <code>p</code>th percentile of the values
499         * in the <code>values</code> array.
500         * <p>
501         * <ul>
502         * <li>Returns <code>Double.NaN</code> if <code>values</code> has length
503         * <code>0</code></li></p>
504         * <li>Returns (for any value of <code>p</code>) <code>values[0]</code>
505         *  if <code>values</code> has length <code>1</code></li>
506         * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
507         * is null  or p is not a valid quantile value (p must be greater than 0
508         * and less than or equal to 100)</li>
509         * </ul></p>
510         * <p>
511         * See {@link org.apache.commons.math.stat.descriptive.rank.Percentile} for
512         * a description of the percentile estimation algorithm used.</p>
513         *
514         * @param values input array of values
515         * @param p the percentile value to compute
516         * @return the percentile value or Double.NaN if the array is empty
517         * @throws IllegalArgumentException if <code>values</code> is null
518         * or p is invalid
519         */
520        public static double percentile(final double[] values, final double p) {
521                return PERCENTILE.evaluate(values,p);
522        }
523    
524         /**
525         * Returns an estimate of the <code>p</code>th percentile of the values
526         * in the <code>values</code> array, starting with the element in (0-based)
527         * position <code>begin</code> in the array and including <code>length</code>
528         * values.
529         * <p>
530         * <ul>
531         * <li>Returns <code>Double.NaN</code> if <code>length = 0</code></li>
532         * <li>Returns (for any value of <code>p</code>) <code>values[begin]</code>
533         *  if <code>length = 1 </code></li>
534         * <li>Throws <code>IllegalArgumentException</code> if <code>values</code>
535         *  is null , <code>begin</code> or <code>length</code> is invalid, or
536         * <code>p</code> is not a valid quantile value (p must be greater than 0
537         * and less than or equal to 100)</li>
538         * </ul></p>
539         * <p>
540          * See {@link org.apache.commons.math.stat.descriptive.rank.Percentile} for
541          * a description of the percentile estimation algorithm used.</p>
542         *
543         * @param values array of input values
544         * @param p  the percentile to compute
545         * @param begin  the first (0-based) element to include in the computation
546         * @param length  the number of array elements to include
547         * @return  the percentile value
548         * @throws IllegalArgumentException if the parameters are not valid or the
549         * input array is null
550         */
551        public static double percentile(final double[] values, final int begin,
552                final int length, final double p) {
553            return PERCENTILE.evaluate(values, begin, length, p);
554        }
555    
556        /**
557         * Returns the sum of the (signed) differences between corresponding elements of the
558         * input arrays -- i.e., sum(sample1[i] - sample2[i]).
559         *
560         * @param sample1  the first array
561         * @param sample2  the second array
562         * @return sum of paired differences
563         * @throws IllegalArgumentException if the arrays do not have the same
564         * (positive) length
565         */
566        public static double sumDifference(final double[] sample1, final double[] sample2)
567            throws IllegalArgumentException {
568            int n = sample1.length;
569            if (n  != sample2.length) {
570                throw MathRuntimeException.createIllegalArgumentException(
571                      LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, n, sample2.length);
572            }
573            if (n < 1) {
574                throw MathRuntimeException.createIllegalArgumentException(
575                      LocalizedFormats.INSUFFICIENT_DIMENSION, sample2.length, 1);
576            }
577            double result = 0;
578            for (int i = 0; i < n; i++) {
579                result += sample1[i] - sample2[i];
580            }
581            return result;
582        }
583    
584        /**
585         * Returns the mean of the (signed) differences between corresponding elements of the
586         * input arrays -- i.e., sum(sample1[i] - sample2[i]) / sample1.length.
587         *
588         * @param sample1  the first array
589         * @param sample2  the second array
590         * @return mean of paired differences
591         * @throws IllegalArgumentException if the arrays do not have the same
592         * (positive) length
593         */
594        public static double meanDifference(final double[] sample1, final double[] sample2)
595        throws IllegalArgumentException {
596            return sumDifference(sample1, sample2) / sample1.length;
597        }
598    
599        /**
600         * Returns the variance of the (signed) differences between corresponding elements of the
601         * input arrays -- i.e., var(sample1[i] - sample2[i]).
602         *
603         * @param sample1  the first array
604         * @param sample2  the second array
605         * @param meanDifference   the mean difference between corresponding entries
606         * @see #meanDifference(double[],double[])
607         * @return variance of paired differences
608         * @throws IllegalArgumentException if the arrays do not have the same
609         * length or their common length is less than 2.
610         */
611        public static double varianceDifference(final double[] sample1, final double[] sample2,
612                double meanDifference)  throws IllegalArgumentException {
613            double sum1 = 0d;
614            double sum2 = 0d;
615            double diff = 0d;
616            int n = sample1.length;
617            if (n != sample2.length) {
618                throw MathRuntimeException.createIllegalArgumentException(
619                      LocalizedFormats.DIMENSIONS_MISMATCH_SIMPLE, n, sample2.length);
620            }
621            if (n < 2) {
622                throw MathRuntimeException.createIllegalArgumentException(
623                      LocalizedFormats.INSUFFICIENT_DIMENSION, n, 2);
624            }
625            for (int i = 0; i < n; i++) {
626                diff = sample1[i] - sample2[i];
627                sum1 += (diff - meanDifference) *(diff - meanDifference);
628                sum2 += diff - meanDifference;
629            }
630            return (sum1 - (sum2 * sum2 / n)) / (n - 1);
631        }
632    
633    
634        /**
635         * Normalize (standardize) the series, so in the end it is having a mean of 0 and a standard deviation of 1.
636         *
637         * @param sample sample to normalize
638         * @return normalized (standardized) sample
639         * @since 2.2
640         */
641        public static double[] normalize(final double[] sample) {
642            DescriptiveStatistics stats = new DescriptiveStatistics();
643    
644            // Add the data from the series to stats
645            for (int i = 0; i < sample.length; i++) {
646                stats.addValue(sample[i]);
647            }
648    
649            // Compute mean and standard deviation
650            double mean = stats.getMean();
651            double standardDeviation = stats.getStandardDeviation();
652    
653            // initialize the standardizedSample, which has the same length as the sample
654            double[] standardizedSample = new double[sample.length];
655    
656            for (int i = 0; i < sample.length; i++) {
657                // z = (x- mean)/standardDeviation
658                standardizedSample[i] = (sample[i] - mean) / standardDeviation;
659            }
660            return standardizedSample;
661        }
662    
663    }