From 7c0d009b46057050172b63e4f3713610a6361d24 Mon Sep 17 00:00:00 2001 From: David Prince Date: Fri, 27 Dec 2013 20:27:42 +0800 Subject: [PATCH 1/3] ValidateMean unit test for Categorical dist Unit tests to validate Categorical.Mean. Currently they fail, indicating that Categorical.Mean is not correctly implemented. Unit tests for StdDev, Variance, Entropy, and Median properties are still required. --- .../Discrete/CategoricalTests.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs index 34cb76b1..67d2e9e4 100644 --- a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs +++ b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs @@ -155,6 +155,22 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Discrete Assert.Throws(() => b.P = _badP); } + /// + /// Validate mean. + /// + /// An array of nonnegative ratios. + /// Expected value. + [TestCase(new double[] { 0, 0.25, 0.5, 0.25 }, 2)] + [TestCase(new double[] { 0, 1, 2, 1 }, 2)] + [TestCase(new double[] { 0, 0.5, 0.5 }, 1.5)] + [TestCase(new double[] { 0.75, 0.25 }, 0.25)] + [TestCase(new double[] { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, 5)] + public void ValidateMean(double[] p, double mean) + { + var n = new Categorical(p); + AssertHelpers.AlmostEqual(mean, n.Mean, 14); + } + /// /// Can sample static. /// From 978824c05026f3fdab902817c70ab4b9cbfb607c Mon Sep 17 00:00:00 2001 From: David Prince Date: Fri, 27 Dec 2013 21:57:42 +0800 Subject: [PATCH 2/3] Fix to Categorical.Mean property. Categorical.Mean was being calculated as _pmfNormalized.Mean(), which is actually the mean probability across all possible values, rather than the mean value of the distribution. I've replaced it with a loop which performs the following standard calculation for mean value: mean = Sum(x * f(x), x=0..N) where f(x) is the probability mass function, and N is the maximum value. An alternate method of calculation is: Mean = Sum( 1 - F(x), x=0..N) or similar[1]. That might be preferable if it results in less computational error, but it's a bit obscure, so for clarity I decided to go with the standard calculation for mean value. [1]: https://en.wikipedia.org/w/index.php?title=Expected_value&oldid=585750484#Discrete_distribution_taking_only_non-negative_integer_values --- src/Numerics/Distributions/Categorical.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/Numerics/Distributions/Categorical.cs b/src/Numerics/Distributions/Categorical.cs index ca98c341..337d74da 100644 --- a/src/Numerics/Distributions/Categorical.cs +++ b/src/Numerics/Distributions/Categorical.cs @@ -216,7 +216,18 @@ namespace MathNet.Numerics.Distributions /// public double Mean { - get { return _pmfNormalized.Mean(); } + get + { + var sum = 0.0; + // Mean = Sum(x * f(x), x=0..N) + // where f(x) is the probability mass function, and N is the maximum value. + for (int i = 0; i < _pmfNormalized.Length; i++) + { + sum += i * _pmfNormalized[i]; + } + + return sum; + } } /// From a7c7b67647e83db13f53a8847025e62fcf7a42cb Mon Sep 17 00:00:00 2001 From: David Prince Date: Sun, 29 Dec 2013 22:46:00 +0800 Subject: [PATCH 3/3] Categorical dist: Tests for Var, SD, and Median Added unit tests to validate the following properties of the Categorical distribution: - Variance, - StdDev, and - Median. TODO: Find out the expected behaviour of Median in ambiguous cases (e.g. where P(X=1)=0.5, and P(X=2)=0.5), then add appropriate unit tests. TODO: Research how to calculate entropy, then add unit tests for the Entropy property. --- .../Discrete/CategoricalTests.cs | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs index 67d2e9e4..b13e0c20 100644 --- a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs +++ b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs @@ -171,6 +171,59 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Discrete AssertHelpers.AlmostEqual(mean, n.Mean, 14); } + /// + /// Validate standard deviation. + /// + /// An array of nonnegative ratios. + /// Standard deviation. + [TestCase(new double[] { 0, 0.25, 0.5, 0.25 }, 0.70710678118654752440084436210485)] + [TestCase(new double[] { 0, 1, 2, 1 }, 0.70710678118654752440084436210485)] + [TestCase(new double[] { 0, 0.5, 0.5 }, 0.5)] + [TestCase(new double[] { 0.75, 0.25 }, 0.43301270189221932338186158537647)] //Sqrt((0.25*0.25)*.75+(.75*.75)*.25) + [TestCase(new double[] { 1, 0, 1 }, 1)] + public void ValidateStdDev(double[] p, double stdDev) + { + var n = new Categorical(p); + AssertHelpers.AlmostEqual(stdDev, n.StdDev, 14); + } + + /// + /// Validate variance. + /// + /// An array of nonnegative ratios. + /// Variance. + [TestCase(new double[] { 0, 0.25, 0.5, 0.25 }, 0.5)] + [TestCase(new double[] { 0, 1, 2, 1 }, 0.5)] + [TestCase(new double[] { 0, 0.5, 0.5 }, 0.25)] + [TestCase(new double[] { 0.75, 0.25 }, 0.1875)] //(0.25*0.25)*.75+(.75*.75)*.25) + [TestCase(new double[] { 1, 0, 1 }, 1)] + public void ValidateVariance(double[] p, double variance) + { + var n = new Categorical(p); + AssertHelpers.AlmostEqual(variance, n.Variance, 14); + } + + /// + /// Validate median. + /// + /// An array of nonnegative ratios. + /// Median. + [TestCase(new double[] { 0, 0.25, 0.5, 0.25 }, 2)] + [TestCase(new double[] { 0, 1, 2, 1 }, 2)] + [TestCase(new double[] { 0.75, 0.25 }, 0)] + // The following test case has median of 5, because: + // P(X < 5) = (1+2+6+3+2)/29 = 14/29 < 0.5. + // P(X <= 5) = 19/29 > 0.5. + [TestCase(new double[] { 1, 2, 6, 3, 2, 5, 1, 1, 0, 1, 7 }, 5)] + // TODO: Find out the expected behavour of Median in ambiguous cases like the following: + //[TestCase(new double[] { 0, 0.5, 0.5 }, ???)] + //[TestCase(new double[] { 1, 0, 1 }, ???)] + public void ValidateMedian(double[] p, int median) + { + var n = new Categorical(p); + Assert.AreEqual(median, n.Median); + } + /// /// Can sample static. ///