diff --git a/src/Numerics/Distributions/Categorical.cs b/src/Numerics/Distributions/Categorical.cs index 5084c966..538b72af 100644 --- a/src/Numerics/Distributions/Categorical.cs +++ b/src/Numerics/Distributions/Categorical.cs @@ -213,7 +213,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; + } } /// diff --git a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs index 9f38c792..70fc55ca 100644 --- a/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs +++ b/src/UnitTests/DistributionTests/Discrete/CategoricalTests.cs @@ -159,6 +159,75 @@ namespace MathNet.Numerics.UnitTests.DistributionTests.Discrete Assert.That(() => b.P = _badP, Throws.ArgumentException); } + /// + /// 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); + } + + /// + /// 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. ///