From e1cf1cc7e667234e4799d2719e74420e2076c4fe Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Thu, 21 Mar 2013 14:44:15 +0100 Subject: [PATCH] Statistics: mean of empty set should be NaN --- src/Numerics/Statistics/Statistics.cs | 180 ++++++------------ .../Statistics/StreamingStatistics.cs | 4 +- .../StatisticsTests/StatisticsTests.cs | 11 ++ 3 files changed, 67 insertions(+), 128 deletions(-) diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index ec992a11..f003987d 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -40,6 +40,53 @@ namespace MathNet.Numerics.Statistics /// public static class Statistics { + /// + /// Returns the minimum value in the sample data. + /// + /// The sample data. + /// The minimum value in the sample data. + public static double Minimum(this IEnumerable data) + { + var array = data as double[]; + return array != null + ? ArrayStatistics.Minimum(array) + : StreamingStatistics.Minimum(data); + } + /// + /// Returns the minimum value in the sample data. + /// + /// The sample data. + /// The minimum value in the sample data. + public static double Minimum(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + return StreamingStatistics.Minimum(data.Where(d => d.HasValue).Select(d => d.Value)); + } + + /// + /// Returns the maximum value in the sample data. + /// + /// The sample data. + /// The maximum value in the sample data. + public static double Maximum(this IEnumerable data) + { + var array = data as double[]; + return array != null + ? ArrayStatistics.Maximum(array) + : StreamingStatistics.Maximum(data); + } + + /// + /// Returns the maximum value in the sample data. + /// + /// The sample data. + /// The maximum value in the sample data. + public static double Maximum(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + return StreamingStatistics.Maximum(data.Where(d => d.HasValue).Select(d => d.Value)); + } + /// /// Calculates the sample mean. /// @@ -47,19 +94,10 @@ namespace MathNet.Numerics.Statistics /// The mean of the sample. public static double Mean(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double mean = 0; - ulong m = 0; - foreach (var item in data) - { - mean += (item - mean) / ++m; - } - - return mean; + var array = data as double[]; + return array != null + ? ArrayStatistics.Mean(array) + : StreamingStatistics.Mean(data); } /// @@ -69,22 +107,8 @@ namespace MathNet.Numerics.Statistics /// The mean of the sample. public static double Mean(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double mean = 0; - ulong m = 0; - foreach (var item in data) - { - if (item.HasValue) - { - mean += (item.Value - mean) / ++m; - } - } - - return mean; + if (data == null) throw new ArgumentNullException("data"); + return StreamingStatistics.Mean(data.Where(d => d.HasValue).Select(d => d.Value)); } /// @@ -321,104 +345,6 @@ namespace MathNet.Numerics.Statistics return Math.Sqrt(PopulationVariance(data)); } - /// - /// Returns the minimum value in the sample data. - /// - /// The sample data. - /// The minimum value in the sample data. - public static double Minimum(this IEnumerable data) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double min = double.MaxValue; - ulong count = 0; - foreach (double? d in data) - { - if (d.HasValue) - { - min = Math.Min(min, d.Value); - count++; - } - } - - return count == 0 ? double.NaN : min; - } - - /// - /// Returns the maximum value in the sample data. - /// - /// The sample data. - /// The maximum value in the sample data. - public static double Maximum(this IEnumerable data) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double max = double.MinValue; - ulong count = 0; - foreach (double? d in data) - { - if (d.HasValue) - { - max = Math.Max(max, d.Value); - count++; - } - } - - return count == 0 ? double.NaN : max; - } - - /// - /// Returns the minimum value in the sample data. - /// - /// The sample data. - /// The minimum value in the sample data. - public static double Minimum(this IEnumerable data) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double min = double.MaxValue; - ulong count = 0; - foreach (double d in data) - { - min = Math.Min(min, d); - count++; - } - - return count == 0 ? double.NaN : min; - } - - /// - /// Returns the maximum value in the sample data. - /// - /// The sample data. - /// The maximum value in the sample data. - public static double Maximum(this IEnumerable data) - { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - double max = double.MinValue; - ulong count = 0; - foreach (double d in data) - { - max = Math.Max(max, d); - count++; - } - - return count == 0 ? double.NaN : max; - } - /// /// Calculates the sample median. /// diff --git a/src/Numerics/Statistics/StreamingStatistics.cs b/src/Numerics/Statistics/StreamingStatistics.cs index 24bf525f..52c676eb 100644 --- a/src/Numerics/Statistics/StreamingStatistics.cs +++ b/src/Numerics/Statistics/StreamingStatistics.cs @@ -90,11 +90,13 @@ namespace MathNet.Numerics.Statistics double mean = 0; ulong m = 0; + bool any = false; foreach (var d in stream) { mean += (d - mean) / ++m; + any = true; } - return mean; + return any ? mean : double.NaN; } } } diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index 04772cec..e462aa8d 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -261,6 +261,17 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.That(StreamingStatistics.Maximum(new[] { 2d }), Is.Not.NaN); } + [Test] + public void MeanOfEmptyMustBeNaN() + { + Assert.That(Statistics.Mean(new double[0]), Is.NaN); + Assert.That(Statistics.Mean(new[] { 2d }), Is.Not.NaN); + Assert.That(ArrayStatistics.Mean(new double[0]), Is.NaN); + Assert.That(ArrayStatistics.Mean(new[] { 2d }), Is.Not.NaN); + Assert.That(StreamingStatistics.Mean(new double[0]), Is.NaN); + Assert.That(StreamingStatistics.Mean(new[] { 2d }), Is.Not.NaN); + } + [Test] public void SampleVarianceOfEmptyAndSingleMustBeNaN() {