Browse Source

Statistics: Streaming Mean

pull/109/head
Christoph Ruegg 14 years ago
parent
commit
7f839739fd
  1. 2
      src/Numerics/Statistics/ArrayStatistics.cs
  2. 22
      src/Numerics/Statistics/StreamingStatistics.cs
  3. 17
      src/UnitTests/StatisticsTests/StatisticsTests.cs

2
src/Numerics/Statistics/ArrayStatistics.cs

@ -80,7 +80,7 @@ namespace MathNet.Numerics.Statistics
} }
/// <summary> /// <summary>
/// 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. /// Returns NaN if data is empty or any entry is NaN.
/// </summary> /// </summary>
/// <param name="data">Sample array, no sorting is assumed.</param> /// <param name="data">Sample array, no sorting is assumed.</param>

22
src/Numerics/Statistics/StreamingStatistics.cs

@ -46,7 +46,7 @@ namespace MathNet.Numerics.Statistics
var min = double.PositiveInfinity; var min = double.PositiveInfinity;
bool any = false; bool any = false;
foreach (double d in stream) foreach (var d in stream)
{ {
if (d < min || double.IsNaN(d)) if (d < min || double.IsNaN(d))
{ {
@ -68,7 +68,7 @@ namespace MathNet.Numerics.Statistics
var max = double.NegativeInfinity; var max = double.NegativeInfinity;
bool any = false; bool any = false;
foreach (double d in stream) foreach (var d in stream)
{ {
if (d > max || double.IsNaN(d)) if (d > max || double.IsNaN(d))
{ {
@ -78,5 +78,23 @@ namespace MathNet.Numerics.Statistics
} }
return any ? max : double.NaN; return any ? max : double.NaN;
} }
/// <summary>
/// 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.
/// </summary>
/// <param name="stream">Sample stream, no sorting is assumed.</param>
public static double Mean(IEnumerable<double> 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;
}
} }
} }

17
src/UnitTests/StatisticsTests/StatisticsTests.cs

@ -86,6 +86,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
Assert.Throws<ArgumentNullException>(() => StreamingStatistics.Minimum(data)); Assert.Throws<ArgumentNullException>(() => StreamingStatistics.Minimum(data));
Assert.Throws<ArgumentNullException>(() => StreamingStatistics.Maximum(data)); Assert.Throws<ArgumentNullException>(() => StreamingStatistics.Maximum(data));
Assert.Throws<ArgumentNullException>(() => StreamingStatistics.Mean(data));
} }
[Test] [Test]
@ -119,6 +120,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
Assert.DoesNotThrow(() => StreamingStatistics.Minimum(data)); Assert.DoesNotThrow(() => StreamingStatistics.Minimum(data));
Assert.DoesNotThrow(() => StreamingStatistics.Maximum(data)); Assert.DoesNotThrow(() => StreamingStatistics.Maximum(data));
Assert.DoesNotThrow(() => StreamingStatistics.Mean(data));
} }
[TestCase("lottery")] [TestCase("lottery")]
@ -134,6 +136,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
var data = _data[dataSet]; var data = _data[dataSet];
AssertHelpers.AlmostEqual(data.Mean, Statistics.Mean(data.Data), 15); AssertHelpers.AlmostEqual(data.Mean, Statistics.Mean(data.Data), 15);
AssertHelpers.AlmostEqual(data.Mean, ArrayStatistics.Mean(data.Data), 15); AssertHelpers.AlmostEqual(data.Mean, ArrayStatistics.Mean(data.Data), 15);
AssertHelpers.AlmostEqual(data.Mean, StreamingStatistics.Mean(data.Data), 15);
} }
[TestCase("lottery")] [TestCase("lottery")]
@ -228,11 +231,19 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
AssertHelpers.AlmostEqual(2d, Statistics.StandardDeviation(gaussian.Samples().Take(10000)), 2); 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, ArrayStatistics.Mean(gaussian.Samples().Take(10000).ToArray()), 11);
AssertHelpers.AlmostEqual(1e+9, StreamingStatistics.Mean(gaussian.Samples().Take(10000)), 11);
} }
[Test] [Test]
public void MinimumOfEmptyMustBeNaN() 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 double[0]), Is.NaN);
Assert.That(StreamingStatistics.Minimum(new[] {2d }), Is.Not.NaN); Assert.That(StreamingStatistics.Minimum(new[] {2d }), Is.Not.NaN);
} }
@ -240,6 +251,12 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests
[Test] [Test]
public void MaximumOfEmptyMustBeNaN() 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 double[0]), Is.NaN);
Assert.That(StreamingStatistics.Maximum(new[] { 2d }), Is.Not.NaN); Assert.That(StreamingStatistics.Maximum(new[] { 2d }), Is.Not.NaN);
} }

Loading…
Cancel
Save