This is an automated email from the ASF dual-hosted git repository. aherbert pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-statistics.git
commit 33bd58fb891dd6975a4e6c299329d6adce1782e2 Author: Alex Herbert <[email protected]> AuthorDate: Tue Jan 2 11:05:02 2024 +0000 Use descriptive module to compute statistics --- commons-statistics-inference/pom.xml | 6 + .../statistics/inference/ChiSquareTest.java | 3 +- .../apache/commons/statistics/inference/GTest.java | 3 +- .../statistics/inference/StatisticUtils.java | 149 +++++---------------- .../apache/commons/statistics/inference/TTest.java | 31 +++-- .../statistics/inference/StatisticUtilsTest.java | 71 +++------- .../commons/statistics/inference/TTestTest.java | 30 +++-- 7 files changed, 102 insertions(+), 191 deletions(-) diff --git a/commons-statistics-inference/pom.xml b/commons-statistics-inference/pom.xml index 127e490..aec3258 100644 --- a/commons-statistics-inference/pom.xml +++ b/commons-statistics-inference/pom.xml @@ -44,6 +44,12 @@ <dependencies> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-statistics-descriptive</artifactId> + <version>1.1-SNAPSHOT</version> + </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-statistics-distribution</artifactId> diff --git a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/ChiSquareTest.java b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/ChiSquareTest.java index 49e24aa..eb70b06 100644 --- a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/ChiSquareTest.java +++ b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/ChiSquareTest.java @@ -16,6 +16,7 @@ */ package org.apache.commons.statistics.inference; +import org.apache.commons.statistics.descriptive.LongMean; import org.apache.commons.statistics.distribution.ChiSquaredDistribution; /** @@ -98,7 +99,7 @@ public final class ChiSquareTest { public double statistic(long[] observed) { Arguments.checkValuesRequiredSize(observed.length, 2); Arguments.checkNonNegative(observed); - final double e = StatisticUtils.mean(observed); + final double e = LongMean.of(observed).getAsDouble(); if (e == 0) { throw new InferenceException(InferenceException.NO_DATA); } diff --git a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/GTest.java b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/GTest.java index 4e9ea69..b1f29ea 100644 --- a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/GTest.java +++ b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/GTest.java @@ -17,6 +17,7 @@ package org.apache.commons.statistics.inference; import org.apache.commons.numbers.core.Sum; +import org.apache.commons.statistics.descriptive.LongMean; import org.apache.commons.statistics.distribution.ChiSquaredDistribution; /** @@ -107,7 +108,7 @@ public final class GTest { public double statistic(long[] observed) { Arguments.checkValuesRequiredSize(observed.length, 2); Arguments.checkNonNegative(observed); - final double e = StatisticUtils.mean(observed); + final double e = LongMean.of(observed).getAsDouble(); if (e == 0) { throw new InferenceException(InferenceException.NO_DATA); } diff --git a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/StatisticUtils.java b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/StatisticUtils.java index 7aaae5e..f618412 100644 --- a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/StatisticUtils.java +++ b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/StatisticUtils.java @@ -21,6 +21,7 @@ import java.util.Collection; import java.util.stream.IntStream; import org.apache.commons.numbers.core.DD; import org.apache.commons.numbers.core.Precision; +import org.apache.commons.statistics.descriptive.Mean; /** * Utility computation methods. @@ -120,33 +121,13 @@ final class StatisticUtils { sum.add(DD.of(v)); } - /** - * Returns the arithmetic mean of the entries in the input array, - * or {@code NaN} if the array is empty. - * - * @param x Values. - * @return the mean of the values or NaN if length = 0 - */ - static double mean(long[] x) { - final int n = x.length; - if (n == 0) { - return Double.NaN; - } - - // Single pass high accuracy sum. The total cannot be more than 2^63 * 2^31 bits - // so can be exactly represented in a double-double. Cumulative error in the sum - // is (n-1) * 4eps with eps = 2^-106. The sum should be exact to double precision. - DD dd = DD.ZERO; - for (final long v : x) { - dd = add(dd, v); - } - - return dd.divide(n).doubleValue(); - } + // Specialised statistic methods not directly supported by o.a.c.statistics.descriptive /** - * Returns the arithmetic mean of the entries in the input array, - * or {@code NaN} if the array is empty. + * Returns the arithmetic mean of the entries in the input arrays, + * or {@code NaN} if the combined length of the arrays is zero. + * + * <p>Supports a combined length above the maximum array size. * * <p>A two-pass, corrected algorithm is used, starting with the definitional formula * computed using the array of stored values and then correcting this by adding the @@ -155,88 +136,22 @@ final class StatisticUtils { * Journal of the American Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. * 859-866. * - * @param x Values. - * @return the mean of the values or NaN if length = 0 - */ - static double mean(double[] x) { - final int n = x.length; - // No check for n == 0 -> return NaN. - // This internal method is only called with non-zero length arrays. - // The divide by zero creates NaN anyway. - - // Adapted from org.apache.commons.math4.legacy.stat.descriptive.moment.Mean - // Updated to use a stream to support high-precision summation as the stream maintains - // a rounding-error term during the aggregation. This is important - // when summing differences which can create cancellation: x + -x => 0. - - // Compute initial estimate using definitional formula - final double mean = Arrays.stream(x).sum() / n; - - // Compute correction factor in second pass - return mean + Arrays.stream(x).map(v -> v - mean).sum() / n; - } - - /** - * Returns the arithmetic mean of the entries in the input arrays, - * or {@code NaN} if the combined length of the arrays is zero. - * - * <p>This is the equivalent of using {@link #mean(double[])} with all the samples - * concatenated into a single array. Supports a combined length above the maximum array - * size. - * * @param samples Values. * @return the mean of the values or NaN if length = 0 - * @see #mean(double[]) */ static double mean(Collection<double[]> samples) { - // See above for computation details + final double mean = samples.stream() + .map(Mean::of) + .reduce(Mean::combine) + .orElseGet(() -> Mean.create()) + .getAsDouble(); + // Second-pass correction. + // Note: The correction may not be finite in the event of extreme values. + // In this case the calling method computation will fail when the mean + // is used and we do not check for overflow here. final long n = samples.stream().mapToInt(x -> x.length).sum(); - final double mean = samples.stream().flatMapToDouble(Arrays::stream).sum() / n; - return mean + samples.stream().flatMapToDouble(Arrays::stream).map(v -> v - mean).sum() / n; - } - - /** - * Returns the variance of the entries in the input array, or {@code NaN} if the array - * is empty. - * - * <p>This method returns the bias-corrected sample variance (using {@code n - 1} in - * the denominator). - * - * <p>Uses a two-pass algorithm. Specifically, these methods use the "corrected - * two-pass algorithm" from Chan, Golub, Levesque, <i>Algorithms for Computing the - * Sample Variance</i>, American Statistician, vol. 37, no. 3 (1983) pp. - * 242-247. - * - * <p>Returns 0 for a single-value (i.e. length = 1) sample. - * - * @param x Values. - * @param mean the mean of the input array - * @return the variance of the values or NaN if the array is empty - */ - static double variance(double[] x, double mean) { - final int n = x.length; - // No check for n == 0 -> return NaN. - // This internal method is only called with non-zero length arrays. - // The input mean of NaN for zero length creates NaN anyway. - if (n == 1) { - return 0; - } - - // Adapted from org.apache.commons.math4.legacy.stat.descriptive.moment.Variance - // Use a stream to accumulate the sum of deviations in high precision. - // This compensation term for the sum of deviations from the mean -> 0. - // We sum the squares in standard precision as there is no cancellation of summands. - final double[] sumSq = {0}; - final double sum2 = Arrays.stream(x).map(v -> { - final double dx = v - mean; - sumSq[0] += dx * dx; - return dx; - }).sum(); - - final double sum1 = sumSq[0]; - // Bias corrected - // Note: variance ~ sum1 / (n-1) but with a correction term sum2 - return (sum1 - (sum2 * sum2 / n)) / (n - 1); + return mean + samples.stream() + .flatMapToDouble(Arrays::stream).map(v -> v - mean).sum() / n; } /** @@ -247,37 +162,46 @@ final class StatisticUtils { * sum(x[i] - y[i]) / x.length * </pre> * - * <p>This computes the same result as creating an array {@code z = x - y} - * and calling {@link #mean(double[]) mean(z)}, but without the intermediate array - * allocation. + * <p>This method avoids intermediate array allocation. + * + * <p>A two-pass, corrected algorithm is used, starting with the definitional formula + * computed using the array of stored values and then correcting this by adding the + * mean deviation of the data values from the arithmetic mean. See, e.g. "Comparison + * of Several Algorithms for Computing Sample Means and Variances," Robert F. Ling, + * Journal of the American Statistical Association, Vol. 69, No. 348 (Dec., 1974), pp. + * 859-866. * * @param x First array. * @param y Second array. * @return mean of paired differences * @throws IllegalArgumentException if the arrays do not have the same length. - * @see #mean(double[]) */ static double meanDifference(double[] x, double[] y) { final int n = x.length; if (n != y.length) { throw new InferenceException(InferenceException.VALUES_MISMATCH, n, y.length); } - // See mean(double[]) for details. final double mean = IntStream.range(0, n).mapToDouble(i -> x[i] - y[i]).sum() / n; return mean + IntStream.range(0, n).mapToDouble(i -> (x[i] - y[i]) - mean).sum() / n; } /** * Returns the variance of the (signed) differences between corresponding elements of - * the input arrays. + * the input arrays, or {@code NaN} if the arrays are empty. * * <pre> * var(x[i] - y[i]) * </pre> * - * <p>This computes the same result as creating an array {@code z = x - y} - * and calling {@link #variance(double[], double) variance(z, mean(z))}, but without the - * intermediate array allocation. + * <p>Returns the bias-corrected sample variance (using {@code n - 1} in the denominator). + * Returns 0 for a single-value (i.e. length = 1) sample. + * + * <p>This method avoids intermediate array allocation. + * + * <p>Uses a two-pass algorithm. Specifically, these methods use the "corrected + * two-pass algorithm" from Chan, Golub, Levesque, <i>Algorithms for Computing the + * Sample Variance</i>, American Statistician, vol. 37, no. 3 (1983) pp. + * 242-247. * * @param x First array. * @param y Second array. @@ -285,14 +209,12 @@ final class StatisticUtils { * @return variance of paired differences * @throws IllegalArgumentException if the arrays do not have the same length. * @see #meanDifference(double[], double[]) - * @see #variance(double[], double) */ static double varianceDifference(double[] x, double[] y, double mean) { final int n = x.length; if (n != y.length) { throw new InferenceException(InferenceException.VALUES_MISMATCH, n, y.length); } - // See variance(double[]) for details. if (n == 1) { return 0; } @@ -302,6 +224,7 @@ final class StatisticUtils { sumSq[0] += dx * dx; return dx; }).sum(); + // sum-of-squared deviations = sum(x^2) - sum(x)^2 / n final double sum1 = sumSq[0]; return (sum1 - (sum2 * sum2 / n)) / (n - 1); } diff --git a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/TTest.java b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/TTest.java index 9b15769..25c654d 100644 --- a/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/TTest.java +++ b/commons-statistics-inference/src/main/java/org/apache/commons/statistics/inference/TTest.java @@ -16,7 +16,10 @@ */ package org.apache.commons.statistics.inference; +import java.util.EnumSet; import java.util.Objects; +import org.apache.commons.statistics.descriptive.DoubleStatistics; +import org.apache.commons.statistics.descriptive.Statistic; import org.apache.commons.statistics.distribution.TDistribution; /** @@ -178,8 +181,10 @@ public final class TTest { */ public double statistic(double[] x) { final long n = checkSampleSize(x.length); - final double m = StatisticUtils.mean(x); - final double v = StatisticUtils.variance(x, m); + final DoubleStatistics s = DoubleStatistics.of( + EnumSet.of(Statistic.MEAN, Statistic.VARIANCE), x); + final double m = s.getAsDouble(Statistic.MEAN); + final double v = s.getAsDouble(Statistic.VARIANCE); return computeT(m - mu, v, n); } @@ -263,10 +268,13 @@ public final class TTest { public double statistic(double[] x, double[] y) { final long n1 = checkSampleSize(x.length); final long n2 = checkSampleSize(y.length); - final double m1 = StatisticUtils.mean(x); - final double m2 = StatisticUtils.mean(y); - final double v1 = StatisticUtils.variance(x, m1); - final double v2 = StatisticUtils.variance(y, m2); + final DoubleStatistics.Builder b = DoubleStatistics.builder(Statistic.MEAN, Statistic.VARIANCE); + final DoubleStatistics s1 = b.build(x); + final double m1 = s1.getAsDouble(Statistic.MEAN); + final double v1 = s1.getAsDouble(Statistic.VARIANCE); + final DoubleStatistics s2 = b.build(y); + final double m2 = s2.getAsDouble(Statistic.MEAN); + final double v2 = s2.getAsDouble(Statistic.VARIANCE); return equalVariances ? computeHomoscedasticT(mu, m1, v1, n1, m2, v2, n2) : computeT(mu, m1, v1, n1, m2, v2, n2); @@ -387,10 +395,13 @@ public final class TTest { // requires the variance. So repeat the computation and compute p. final long n1 = checkSampleSize(x.length); final long n2 = checkSampleSize(y.length); - final double m1 = StatisticUtils.mean(x); - final double m2 = StatisticUtils.mean(y); - final double v1 = StatisticUtils.variance(x, m1); - final double v2 = StatisticUtils.variance(y, m2); + final DoubleStatistics.Builder b = DoubleStatistics.builder(Statistic.MEAN, Statistic.VARIANCE); + final DoubleStatistics s1 = b.build(x); + final double m1 = s1.getAsDouble(Statistic.MEAN); + final double v1 = s1.getAsDouble(Statistic.VARIANCE); + final DoubleStatistics s2 = b.build(y); + final double m2 = s2.getAsDouble(Statistic.MEAN); + final double v2 = s2.getAsDouble(Statistic.VARIANCE); double t; double df; if (equalVariances) { diff --git a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/StatisticUtilsTest.java b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/StatisticUtilsTest.java index ac2e276..d44a6d6 100644 --- a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/StatisticUtilsTest.java +++ b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/StatisticUtilsTest.java @@ -16,9 +16,7 @@ */ package org.apache.commons.statistics.inference; -import java.math.BigDecimal; import java.math.BigInteger; -import java.math.MathContext; import java.util.Arrays; import java.util.function.BiConsumer; import java.util.stream.IntStream; @@ -90,6 +88,10 @@ class StatisticUtilsTest { TestUtils.assertThrowsWithMessage(IllegalArgumentException.class, () -> action.accept(new double[] {1, 1}, new long[] {1}), "values", "size"); + // Observed is zero + TestUtils.assertThrowsWithMessage(IllegalArgumentException.class, + () -> action.accept(new double[] {1, 1}, new long[] {0, 0}), "no", "data"); + // Samples not same size, i.e. cannot be paired TestUtils.assertThrowsWithMessage(IllegalArgumentException.class, () -> action.accept(new double[] {1, 1}, new long[] {1, 2, 3}), "values", "size", "mismatch"); @@ -118,9 +120,11 @@ class StatisticUtilsTest { @MethodSource void testComputeRatio(double[] e, long[] o) { final double ratio = StatisticUtils.computeRatio(e, o); - final long sum1 = Arrays.stream(o).sum(); + // Sum as an exact double + final double sum1 = Arrays.stream(o).mapToObj(BigInteger::valueOf) + .reduce(BigInteger.ZERO, BigInteger::add).doubleValue(); final double sum2 = Arrays.stream(e).map(x -> x * ratio).sum(); - TestUtils.assertRelativelyEquals(sum1, sum2, Math.ulp(1.0), "rescaled sum(e) != sum(o)"); + TestUtils.assertRelativelyEquals(sum1, sum2, Math.ulp(sum1), "rescaled sum(e) != sum(o)"); } static Stream<Arguments> testComputeRatio() { @@ -148,6 +152,8 @@ class StatisticUtilsTest { final UniformRandomProvider rng = RandomSource.XO_RO_SHI_RO_128_PP.create(123); for (int n = 2; n < 1024; n *= 2) { builder.add(Arguments.of(rng.doubles(n).toArray(), rng.longs(n, 0, Integer.MAX_VALUE).toArray())); + // values that are not integers + builder.add(Arguments.of(rng.doubles(n).toArray(), rng.longs(n).map(x -> x >>> 1).toArray())); } return builder.build(); } @@ -155,10 +161,9 @@ class StatisticUtilsTest { @Test void testMeanAndVarianceSize0() { final double[] data = {}; - Assertions.assertEquals(Double.NaN, StatisticUtils.mean(new long[0]), "mean(long[])"); - Assertions.assertEquals(Double.NaN, StatisticUtils.mean(data), "mean"); - Assertions.assertEquals(Double.NaN, StatisticUtils.mean(Arrays.asList(data, data, data)), "mean"); - Assertions.assertEquals(Double.NaN, StatisticUtils.variance(data, 0), "variance"); + Assertions.assertEquals(Double.NaN, StatisticUtils.mean(Arrays.asList()), "mean (empty)"); + Assertions.assertEquals(Double.NaN, StatisticUtils.mean(Arrays.asList(data)), "mean (single array)"); + Assertions.assertEquals(Double.NaN, StatisticUtils.mean(Arrays.asList(data, data, data)), "mean (multi array)"); Assertions.assertEquals(Double.NaN, StatisticUtils.meanDifference(data, data), "meanDifference"); Assertions.assertEquals(Double.NaN, StatisticUtils.varianceDifference(data, data, 0), "varianceDifference"); } @@ -176,15 +181,12 @@ class StatisticUtilsTest { @ParameterizedTest @MethodSource void testMeanAndVariance(double[] data, double mean, double variance) { - final double m1 = StatisticUtils.mean(data); - final double v1 = StatisticUtils.variance(data, m1); - Assertions.assertEquals(mean, m1, Math.abs(mean) * 1e-15, "mean"); - Assertions.assertEquals(variance, v1, variance * 1e-15, "variance"); + final double deltaMean = Math.abs(mean) * 1e-15; // For the multiple array mean, split the array final double[] x = Arrays.copyOf(data, data.length / 2); final double[] y = Arrays.copyOfRange(data, data.length / 2, data.length); - Assertions.assertEquals(m1, StatisticUtils.mean(Arrays.asList(x, y)), "mean(x, y)"); + Assertions.assertEquals(mean, StatisticUtils.mean(Arrays.asList(x, y)), deltaMean, "mean(x, y)"); // For the difference computation construct input so that data = data1 - data2. // This is simple if data1 = data and data2 is all zero but here @@ -194,13 +196,8 @@ class StatisticUtilsTest { final double[] data2 = IntStream.range(0, data.length).mapToDouble(i -> i + c).toArray(); final double m2 = StatisticUtils.meanDifference(data1, data2); final double v2 = StatisticUtils.varianceDifference(data1, data2, m2); - // Check absolutely equal to the single array method, - // i.e. the computations should be the same as generating data = data1 - data2 - // and calling the single array methods. - // This works if the input values and the offset are exactly representable - // (no rounding) which is true as the values are integers. - Assertions.assertEquals(m1, m2, "meanDifference"); - Assertions.assertEquals(v1, v2, "varianceDifference"); + Assertions.assertEquals(mean, m2, deltaMean, "meanDifference"); + Assertions.assertEquals(variance, v2, variance * 1e-15, "varianceDifference"); } static Stream<Arguments> testMeanAndVariance() { @@ -213,38 +210,4 @@ class StatisticUtilsTest { Arguments.of(new double[] {-23467824, 23648, 2368, 23749, -23424, -23492, -92397747}, -16551817.42857143, 1195057670342971.2) ); } - - @ParameterizedTest - @MethodSource - void testMeanLong(long[] data) { - final double m1 = StatisticUtils.mean(data); - final BigInteger sum = Arrays.stream(data) - .mapToObj(BigInteger::valueOf) - .reduce(BigInteger.ZERO, BigInteger::add); - final double expected = new BigDecimal(sum) - .divide(BigDecimal.valueOf(data.length), MathContext.DECIMAL128).doubleValue(); - Assertions.assertEquals(expected, m1); - } - - static Stream<Arguments> testMeanLong() { - final Stream.Builder<Arguments> builder = Stream.builder(); - builder.add(Arguments.of(new long[1])); - builder.add(Arguments.of(new long[] {42})); - final UniformRandomProvider rng = RandomSource.XO_RO_SHI_RO_128_PP.create(); - // int values - builder.add(Arguments.of(rng.ints(5).asLongStream().toArray())); - builder.add(Arguments.of(rng.ints(25).asLongStream().toArray())); - builder.add(Arguments.of(rng.ints(50).asLongStream().toArray())); - - // Note: This data is failed by Arrays.stream(data).average().getAsDouble(); - // long values without cancellation (all positive) - builder.add(Arguments.of(rng.longs(5).map(x -> x >>> 1).toArray())); - builder.add(Arguments.of(rng.longs(50).map(x -> x >>> 1).toArray())); - builder.add(Arguments.of(rng.longs(500).map(x -> x >>> 1).toArray())); - // long values with cancellation - builder.add(Arguments.of(rng.longs(5).toArray())); - builder.add(Arguments.of(rng.longs(50).toArray())); - builder.add(Arguments.of(rng.longs(500).toArray())); - return builder.build(); - } } diff --git a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/TTestTest.java b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/TTestTest.java index c5961a0..07f050b 100644 --- a/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/TTestTest.java +++ b/commons-statistics-inference/src/test/java/org/apache/commons/statistics/inference/TTestTest.java @@ -16,9 +16,12 @@ */ package org.apache.commons.statistics.inference; +import java.util.EnumSet; import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.stream.Stream; +import org.apache.commons.statistics.descriptive.DoubleStatistics; +import org.apache.commons.statistics.descriptive.Statistic; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -95,8 +98,10 @@ class TTestTest { final Object[] args = a.get(); final double[] sample = (double[]) args[1]; final Object[] args2 = new Object[args.length + 2]; - final double m = StatisticUtils.mean(sample); - final double v = StatisticUtils.variance(sample, m); + final DoubleStatistics s = DoubleStatistics.of( + EnumSet.of(Statistic.MEAN, Statistic.VARIANCE), sample); + final double m = s.getAsDouble(Statistic.MEAN); + final double v = s.getAsDouble(Statistic.VARIANCE); args2[0] = args[0]; args2[1] = m; args2[2] = v; @@ -308,18 +313,19 @@ class TTestTest { // This provides data with an expected mean (mu) for the two sample dataset method. return testTwoSample().map(a -> { final Object[] args = a.get(); - final double[] s1 = (double[]) args[1]; - final double[] s2 = (double[]) args[2]; + final double[] x = (double[]) args[1]; + final double[] y = (double[]) args[2]; final Object[] args2 = new Object[args.length + 4]; - final double m1 = StatisticUtils.mean(s1); - final double m2 = StatisticUtils.mean(s2); + final DoubleStatistics.Builder b = DoubleStatistics.builder(Statistic.MEAN, Statistic.VARIANCE); + final DoubleStatistics s1 = b.build(x); + final DoubleStatistics s2 = b.build(y); args2[0] = args[0]; - args2[1] = m1; - args2[2] = StatisticUtils.variance(s1, m1); - args2[3] = s1.length; - args2[4] = m2; - args2[5] = StatisticUtils.variance(s2, m2); - args2[6] = s2.length; + args2[1] = s1.getAsDouble(Statistic.MEAN); + args2[2] = s1.getAsDouble(Statistic.VARIANCE); + args2[3] = x.length; + args2[4] = s2.getAsDouble(Statistic.MEAN); + args2[5] = s2.getAsDouble(Statistic.VARIANCE); + args2[6] = y.length; System.arraycopy(args, 3, args2, 7, args.length - 3); return Arguments.of(args2); });
