diff --git a/src/Numerics/Statistics/ArrayStatistics.cs b/src/Numerics/Statistics/ArrayStatistics.cs index 9383347c..b304a5c2 100644 --- a/src/Numerics/Statistics/ArrayStatistics.cs +++ b/src/Numerics/Statistics/ArrayStatistics.cs @@ -80,7 +80,7 @@ namespace MathNet.Numerics.Statistics } /// - /// Returns the sample mean from the unsorted data array. + /// Returns the arithmetic sample mean from the unsorted data array. /// Returns NaN if data is empty or any entry is NaN. /// /// Sample array, no sorting is assumed. diff --git a/src/Numerics/Statistics/StreamingStatistics.cs b/src/Numerics/Statistics/StreamingStatistics.cs index 057c7e12..24bf525f 100644 --- a/src/Numerics/Statistics/StreamingStatistics.cs +++ b/src/Numerics/Statistics/StreamingStatistics.cs @@ -46,7 +46,7 @@ namespace MathNet.Numerics.Statistics var min = double.PositiveInfinity; bool any = false; - foreach (double d in stream) + foreach (var d in stream) { if (d < min || double.IsNaN(d)) { @@ -68,7 +68,7 @@ namespace MathNet.Numerics.Statistics var max = double.NegativeInfinity; bool any = false; - foreach (double d in stream) + foreach (var d in stream) { if (d > max || double.IsNaN(d)) { @@ -78,5 +78,23 @@ namespace MathNet.Numerics.Statistics } return any ? max : double.NaN; } + + /// + /// Returns the arithmetic sample mean from the enumerable, in a single pass without memoization. + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample stream, no sorting is assumed. + public static double Mean(IEnumerable stream) + { + if (stream == null) throw new ArgumentNullException("stream"); + + double mean = 0; + ulong m = 0; + foreach (var d in stream) + { + mean += (d - mean) / ++m; + } + return mean; + } } } diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index eafd6cf2..04772cec 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -86,6 +86,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.Throws(() => StreamingStatistics.Minimum(data)); Assert.Throws(() => StreamingStatistics.Maximum(data)); + Assert.Throws(() => StreamingStatistics.Mean(data)); } [Test] @@ -119,6 +120,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.DoesNotThrow(() => StreamingStatistics.Minimum(data)); Assert.DoesNotThrow(() => StreamingStatistics.Maximum(data)); + Assert.DoesNotThrow(() => StreamingStatistics.Mean(data)); } [TestCase("lottery")] @@ -134,6 +136,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var data = _data[dataSet]; AssertHelpers.AlmostEqual(data.Mean, Statistics.Mean(data.Data), 15); AssertHelpers.AlmostEqual(data.Mean, ArrayStatistics.Mean(data.Data), 15); + AssertHelpers.AlmostEqual(data.Mean, StreamingStatistics.Mean(data.Data), 15); } [TestCase("lottery")] @@ -228,11 +231,19 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests AssertHelpers.AlmostEqual(2d, Statistics.StandardDeviation(gaussian.Samples().Take(10000)), 2); AssertHelpers.AlmostEqual(1e+9, ArrayStatistics.Mean(gaussian.Samples().Take(10000).ToArray()), 11); + + AssertHelpers.AlmostEqual(1e+9, StreamingStatistics.Mean(gaussian.Samples().Take(10000)), 11); } [Test] public void MinimumOfEmptyMustBeNaN() { + Assert.That(Statistics.Minimum(new double[0]), Is.NaN); + Assert.That(Statistics.Minimum(new[] { 2d }), Is.Not.NaN); + Assert.That(ArrayStatistics.Minimum(new double[0]), Is.NaN); + Assert.That(ArrayStatistics.Minimum(new[] { 2d }), Is.Not.NaN); + Assert.That(SortedArrayStatistics.Minimum(new double[0]), Is.NaN); + Assert.That(SortedArrayStatistics.Minimum(new[] { 2d }), Is.Not.NaN); Assert.That(StreamingStatistics.Minimum(new double[0]), Is.NaN); Assert.That(StreamingStatistics.Minimum(new[] {2d }), Is.Not.NaN); } @@ -240,6 +251,12 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests [Test] public void MaximumOfEmptyMustBeNaN() { + Assert.That(Statistics.Maximum(new double[0]), Is.NaN); + Assert.That(Statistics.Maximum(new[] { 2d }), Is.Not.NaN); + Assert.That(ArrayStatistics.Maximum(new double[0]), Is.NaN); + Assert.That(ArrayStatistics.Maximum(new[] { 2d }), Is.Not.NaN); + Assert.That(SortedArrayStatistics.Maximum(new double[0]), Is.NaN); + Assert.That(SortedArrayStatistics.Maximum(new[] { 2d }), Is.Not.NaN); Assert.That(StreamingStatistics.Maximum(new double[0]), Is.NaN); Assert.That(StreamingStatistics.Maximum(new[] { 2d }), Is.Not.NaN); }