From 9d4d838638c7ee0c6f89c8061e89ed08171ee304 Mon Sep 17 00:00:00 2001 From: Gilles Sadowski Date: Mon, 31 May 2021 03:37:22 +0200 Subject: [PATCH] MATH-1431: Avoid NaN in case of empty bin. Thanks to Artem Onuchin. Closes #79. --- .../distribution/EmpiricalDistribution.java | 3 ++- .../EmpiricalDistributionTest.java | 23 ++++++++++++++++++- src/changes/changes.xml | 3 +++ 3 files changed, 27 insertions(+), 2 deletions(-) diff --git a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistribution.java b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistribution.java index 041f21f03..4a697bbc5 100644 --- a/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistribution.java +++ b/commons-math-legacy/src/main/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistribution.java @@ -743,7 +743,8 @@ public class EmpiricalDistribution extends AbstractRealDistribution * @return within-bin kernel parameterized by bStats */ protected ContinuousDistribution getKernel(SummaryStatistics bStats) { - if (bStats.getN() == 1 || bStats.getVariance() == 0) { + if (bStats.getN() <= 1 || + bStats.getVariance() == 0) { return new ConstantContinuousDistribution(bStats.getMean()); } else { return new NormalDistribution(bStats.getMean(), bStats.getStandardDeviation()); diff --git a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistributionTest.java b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistributionTest.java index dfdfdd946..5e9e6504c 100644 --- a/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistributionTest.java +++ b/commons-math-legacy/src/test/java/org/apache/commons/math4/legacy/distribution/EmpiricalDistributionTest.java @@ -24,10 +24,13 @@ import java.net.URL; import java.util.ArrayList; import java.util.Arrays; +import org.apache.commons.rng.UniformRandomProvider; +import org.apache.commons.rng.simple.RandomSource; import org.apache.commons.statistics.distribution.ContinuousDistribution; import org.apache.commons.statistics.distribution.ConstantContinuousDistribution; import org.apache.commons.statistics.distribution.UniformContinuousDistribution; import org.apache.commons.statistics.distribution.NormalDistribution; +import org.apache.commons.statistics.distribution.ExponentialDistribution; import org.apache.commons.math4.legacy.TestUtils; import org.apache.commons.math4.legacy.analysis.UnivariateFunction; import org.apache.commons.math4.legacy.analysis.integration.BaseAbstractUnivariateIntegrator; @@ -35,7 +38,6 @@ import org.apache.commons.math4.legacy.analysis.integration.IterativeLegendreGau import org.apache.commons.math4.legacy.exception.MathIllegalStateException; import org.apache.commons.math4.legacy.exception.NullArgumentException; import org.apache.commons.math4.legacy.exception.NotStrictlyPositiveException; -import org.apache.commons.rng.simple.RandomSource; import org.apache.commons.math4.legacy.stat.descriptive.SummaryStatistics; import org.apache.commons.math4.legacy.util.FastMath; import org.junit.Assert; @@ -657,6 +659,25 @@ public final class EmpiricalDistributionTest extends RealDistributionAbstractTes Assert.assertEquals(9.0, dist.inverseCumulativeProbability(0.6), tol); } + @Test + public void testMath1431() { + final UniformRandomProvider rng = RandomSource.create(RandomSource.WELL_19937_C, 1000); + final ContinuousDistribution.Sampler exponentialDistributionSampler + = new ExponentialDistribution(0.05).createSampler(rng); + final double[] empiricalDataPoints = new double[3000]; + for (int i = 0; i < empiricalDataPoints.length; i++) { + empiricalDataPoints[i] = exponentialDistributionSampler.sample(); + } + + final EmpiricalDistribution testDistribution = new EmpiricalDistribution(100); + testDistribution.load(empiricalDataPoints); + + for (int i = 0; i < 1000; i++) { + final double point = rng.nextDouble(); + final double cdf = testDistribution.cumulativeProbability(point); + Assert.assertFalse("point: " + point, Double.isNaN(cdf)); + } + } /** * Empirical distribution using a constant smoothing kernel. diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c8912d5f1..68f4c05bc 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -86,6 +86,9 @@ Caveat: nightmare was one of the main reasons for creating more focused components.] "> + + "EmpiricalDistribution" handles empty bin. + Transforms codes moved into a dedicated maven module.