From 77ace8c7ec61ac741c07b8d100466e45b544eaef Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Thu, 21 Mar 2013 15:27:53 +0100 Subject: [PATCH] Statistics: Array and Streaming Sample and Population StandardDeviation --- src/Numerics/Statistics/ArrayStatistics.cs | 22 ++++++++++++ src/Numerics/Statistics/Statistics.cs | 36 +++++++------------ .../Statistics/StreamingStatistics.cs | 22 ++++++++++++ .../StatisticsTests/StatisticsTests.cs | 12 +++++++ 4 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/Numerics/Statistics/ArrayStatistics.cs b/src/Numerics/Statistics/ArrayStatistics.cs index ccb5afb4..6e41011d 100644 --- a/src/Numerics/Statistics/ArrayStatistics.cs +++ b/src/Numerics/Statistics/ArrayStatistics.cs @@ -120,6 +120,17 @@ namespace MathNet.Numerics.Statistics return variance/(data.Length - 1); } + /// + /// Estimates the unbiased population or sample standard deviation from the unsorted data array. + /// On a dataset of size N will use an N-1 normalizer + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample array, no sorting is assumed. + public static double StandardDeviation(double[] data) + { + return Math.Sqrt(Variance(data)); + } + /// /// Estimates the biased population variance from the unsorted data array. /// On a dataset of size N will use an N normalizer @@ -141,5 +152,16 @@ namespace MathNet.Numerics.Statistics } return variance/data.Length; } + + /// + /// Estimates the biased population standard deviation from the unsorted data array. + /// On a dataset of size N will use an N normalizer + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample array, no sorting is assumed. + public static double PopulationStandardDeviation(double[] data) + { + return Math.Sqrt(PopulationVariance(data)); + } } } \ No newline at end of file diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index 1c345882..2917ab67 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -166,12 +166,10 @@ namespace MathNet.Numerics.Statistics /// The standard deviation of the sample. public static double StandardDeviation(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - return Math.Sqrt(Variance(data)); + var array = data as double[]; + return array != null + ? ArrayStatistics.StandardDeviation(array) + : StreamingStatistics.StandardDeviation(data); } /// @@ -181,12 +179,8 @@ namespace MathNet.Numerics.Statistics /// The standard deviation of the sample. public static double StandardDeviation(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - return Math.Sqrt(Variance(data)); + if (data == null) throw new ArgumentNullException("data"); + return StreamingStatistics.StandardDeviation(data.Where(d => d.HasValue).Select(d => d.Value)); } /// @@ -196,12 +190,10 @@ namespace MathNet.Numerics.Statistics /// The standard deviation of the sample. public static double PopulationStandardDeviation(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - return Math.Sqrt(PopulationVariance(data)); + var array = data as double[]; + return array != null + ? ArrayStatistics.PopulationStandardDeviation(array) + : StreamingStatistics.PopulationStandardDeviation(data); } /// @@ -211,12 +203,8 @@ namespace MathNet.Numerics.Statistics /// The standard deviation of the sample. public static double PopulationStandardDeviation(this IEnumerable data) { - if (data == null) - { - throw new ArgumentNullException("data"); - } - - return Math.Sqrt(PopulationVariance(data)); + if (data == null) throw new ArgumentNullException("data"); + return StreamingStatistics.PopulationStandardDeviation(data.Where(d => d.HasValue).Select(d => d.Value)); } /// diff --git a/src/Numerics/Statistics/StreamingStatistics.cs b/src/Numerics/Statistics/StreamingStatistics.cs index 86146c25..6a60022f 100644 --- a/src/Numerics/Statistics/StreamingStatistics.cs +++ b/src/Numerics/Statistics/StreamingStatistics.cs @@ -132,6 +132,17 @@ namespace MathNet.Numerics.Statistics return j > 1 ? variance/(j - 1) : double.NaN; } + /// + /// Estimates the unbiased population or sample standard deviation from the enumerable, in a single pass without memoization. + /// On a dataset of size N will use an N-1 normalizer + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample stream, no sorting is assumed. + public static double StandardDeviation(IEnumerable stream) + { + return Math.Sqrt(Variance(stream)); + } + /// /// Estimates the biased population variance from the enumerable, in a single pass without memoization. /// On a dataset of size N will use an N normalizer @@ -164,5 +175,16 @@ namespace MathNet.Numerics.Statistics } return variance/j; } + + /// + /// Estimates the biased population standard deviation from the enumerable, in a single pass without memoization. + /// On a dataset of size N will use an N normalizer + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample stream, no sorting is assumed. + public static double PopulationStandardDeviation(IEnumerable stream) + { + return Math.Sqrt(PopulationVariance(stream)); + } } } diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index 7b4e31ef..fe7cfcf7 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -84,13 +84,17 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.Throws(() => ArrayStatistics.Maximum(data)); Assert.Throws(() => ArrayStatistics.Mean(data)); Assert.Throws(() => ArrayStatistics.Variance(data)); + Assert.Throws(() => ArrayStatistics.StandardDeviation(data)); Assert.Throws(() => ArrayStatistics.PopulationVariance(data)); + Assert.Throws(() => ArrayStatistics.PopulationStandardDeviation(data)); Assert.Throws(() => StreamingStatistics.Minimum(data)); Assert.Throws(() => StreamingStatistics.Maximum(data)); Assert.Throws(() => StreamingStatistics.Mean(data)); Assert.Throws(() => StreamingStatistics.Variance(data)); + Assert.Throws(() => StreamingStatistics.StandardDeviation(data)); Assert.Throws(() => StreamingStatistics.PopulationVariance(data)); + Assert.Throws(() => StreamingStatistics.PopulationStandardDeviation(data)); } [Test] @@ -122,13 +126,17 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.DoesNotThrow(() => ArrayStatistics.Maximum(data)); Assert.DoesNotThrow(() => ArrayStatistics.Mean(data)); Assert.DoesNotThrow(() => ArrayStatistics.Variance(data)); + Assert.DoesNotThrow(() => ArrayStatistics.StandardDeviation(data)); Assert.DoesNotThrow(() => ArrayStatistics.PopulationVariance(data)); + Assert.DoesNotThrow(() => ArrayStatistics.PopulationStandardDeviation(data)); Assert.DoesNotThrow(() => StreamingStatistics.Minimum(data)); Assert.DoesNotThrow(() => StreamingStatistics.Maximum(data)); Assert.DoesNotThrow(() => StreamingStatistics.Mean(data)); Assert.DoesNotThrow(() => StreamingStatistics.Variance(data)); + Assert.DoesNotThrow(() => StreamingStatistics.StandardDeviation(data)); Assert.DoesNotThrow(() => StreamingStatistics.PopulationVariance(data)); + Assert.DoesNotThrow(() => StreamingStatistics.PopulationStandardDeviation(data)); } [TestCase("lottery")] @@ -173,6 +181,8 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests { var data = _data[dataSet]; AssertHelpers.AlmostEqual(data.StandardDeviation, Statistics.StandardDeviation(data.Data), digits); + AssertHelpers.AlmostEqual(data.StandardDeviation, ArrayStatistics.StandardDeviation(data.Data), digits); + AssertHelpers.AlmostEqual(data.StandardDeviation, StreamingStatistics.StandardDeviation(data.Data), digits); } [TestCase("lottery", 15)] @@ -240,9 +250,11 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests AssertHelpers.AlmostEqual(1e+9, ArrayStatistics.Mean(gaussian.Samples().Take(10000).ToArray()), 11); AssertHelpers.AlmostEqual(4d, ArrayStatistics.Variance(gaussian.Samples().Take(10000).ToArray()), 1); + AssertHelpers.AlmostEqual(2d, ArrayStatistics.StandardDeviation(gaussian.Samples().Take(10000).ToArray()), 2); AssertHelpers.AlmostEqual(1e+9, StreamingStatistics.Mean(gaussian.Samples().Take(10000)), 11); AssertHelpers.AlmostEqual(4d, StreamingStatistics.Variance(gaussian.Samples().Take(10000)), 1); + AssertHelpers.AlmostEqual(2d, StreamingStatistics.StandardDeviation(gaussian.Samples().Take(10000)), 2); } [Test]