diff --git a/src/Numerics/Statistics/ArrayStatistics.cs b/src/Numerics/Statistics/ArrayStatistics.cs index 80ff3023..8b0bca39 100644 --- a/src/Numerics/Statistics/ArrayStatistics.cs +++ b/src/Numerics/Statistics/ArrayStatistics.cs @@ -163,6 +163,48 @@ namespace MathNet.Numerics.Statistics return mean; } + /// + /// Evaluates the geometric mean of the unsorted data array. + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample array, no sorting is assumed. + public static double GeometricMean(double[] data) + { + if (data.Length == 0) + { + return double.NaN; + } + + double sum = 0; + for (int i = 0; i < data.Length; i++) + { + sum += Math.Log(data[i]); + } + + return Math.Exp(sum/data.Length); + } + + /// + /// Evaluates the harmonic mean of the unsorted data array. + /// Returns NaN if data is empty or any entry is NaN. + /// + /// Sample array, no sorting is assumed. + public static double HarmonicMean(double[] data) + { + if (data.Length == 0) + { + return double.NaN; + } + + double sum = 0; + for (int i = 0; i < data.Length; i++) + { + sum += 1.0/data[i]; + } + + return data.Length/sum; + } + /// /// Estimates the unbiased population variance from the provided samples as unsorted array. /// On a dataset of size N will use an N-1 normalizer (Bessel's correction). diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index 610a51e4..981d2ef5 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -117,6 +117,34 @@ namespace MathNet.Numerics.Statistics return StreamingStatistics.Mean(data.Where(d => d.HasValue).Select(d => d.Value)); } + /// + /// Evaluates the geometric mean. + /// Returns NaN if data is empty or if any entry is NaN. + /// + /// The data to calculate the geometric mean of. + /// The geometric mean of the sample. + public static double GeometricMean(this IEnumerable data) + { + var array = data as double[]; + return array != null + ? ArrayStatistics.GeometricMean(array) + : StreamingStatistics.GeometricMean(data); + } + + /// + /// Evaluates the harmonic mean. + /// Returns NaN if data is empty or if any entry is NaN. + /// + /// The data to calculate the harmonic mean of. + /// The harmonic mean of the sample. + public static double HarmonicMean(this IEnumerable data) + { + var array = data as double[]; + return array != null + ? ArrayStatistics.HarmonicMean(array) + : StreamingStatistics.HarmonicMean(data); + } + /// /// Estimates the unbiased population variance from the provided samples. /// On a dataset of size N will use an N-1 normalizer (Bessel's correction). diff --git a/src/Numerics/Statistics/StreamingStatistics.cs b/src/Numerics/Statistics/StreamingStatistics.cs index d0ba11ec..7ec802bb 100644 --- a/src/Numerics/Statistics/StreamingStatistics.cs +++ b/src/Numerics/Statistics/StreamingStatistics.cs @@ -109,6 +109,44 @@ namespace MathNet.Numerics.Statistics return any ? mean : double.NaN; } + /// + /// Evaluates the geometric mean of 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 GeometricMean(IEnumerable stream) + { + ulong m = 0; + double sum = 0; + + foreach (var d in stream) + { + sum += Math.Log(d); + m++; + } + + return m > 0 ? Math.Exp(sum / m) : double.NaN; + } + + /// + /// Evaluates the harmonic mean of 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 HarmonicMean(IEnumerable stream) + { + ulong m = 0; + double sum = 0; + + foreach (var d in stream) + { + sum += 1.0 / d; + m++; + } + + return m > 0 ? m/sum : double.NaN; + } + /// /// Estimates the unbiased population variance from the provided samples as enumerable sequence, in a single pass without memoization. /// On a dataset of size N will use an N-1 normalizer (Bessel's correction). diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index 64e8023e..3943609f 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -4,7 +4,7 @@ // http://github.com/mathnet/mathnet-numerics // http://mathnetnumerics.codeplex.com // -// Copyright (c) 2009-2014 Math.NET +// Copyright (c) 2009-2015 Math.NET // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation @@ -30,7 +30,6 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using MathNet.Numerics.Distributions; using MathNet.Numerics.Random; @@ -71,6 +70,8 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.That(() => Statistics.Minimum(data), Throws.Exception); Assert.That(() => Statistics.Maximum(data), Throws.Exception); Assert.That(() => Statistics.Mean(data), Throws.Exception); + Assert.That(() => Statistics.HarmonicMean(data), Throws.Exception); + Assert.That(() => Statistics.GeometricMean(data), Throws.Exception); Assert.That(() => Statistics.Median(data), Throws.Exception); Assert.That(() => Statistics.Quantile(data, 0.3), Throws.Exception); Assert.That(() => Statistics.Variance(data), Throws.Exception); @@ -99,6 +100,8 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.That(() => ArrayStatistics.Maximum(data), Throws.Exception.TypeOf()); Assert.That(() => ArrayStatistics.OrderStatisticInplace(data, 1), Throws.Exception.TypeOf()); Assert.That(() => ArrayStatistics.Mean(data), Throws.Exception.TypeOf()); + Assert.That(() => ArrayStatistics.HarmonicMean(data), Throws.Exception.TypeOf()); + Assert.That(() => ArrayStatistics.GeometricMean(data), Throws.Exception.TypeOf()); Assert.That(() => ArrayStatistics.Variance(data), Throws.Exception.TypeOf()); Assert.That(() => ArrayStatistics.StandardDeviation(data), Throws.Exception.TypeOf()); Assert.That(() => ArrayStatistics.PopulationVariance(data), Throws.Exception.TypeOf()); @@ -112,6 +115,8 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.That(() => StreamingStatistics.Minimum(data), Throws.Exception.TypeOf()); Assert.That(() => StreamingStatistics.Maximum(data), Throws.Exception.TypeOf()); Assert.That(() => StreamingStatistics.Mean(data), Throws.Exception.TypeOf()); + Assert.That(() => StreamingStatistics.HarmonicMean(data), Throws.Exception.TypeOf()); + Assert.That(() => StreamingStatistics.GeometricMean(data), Throws.Exception.TypeOf()); Assert.That(() => StreamingStatistics.Variance(data), Throws.Exception.TypeOf()); Assert.That(() => StreamingStatistics.StandardDeviation(data), Throws.Exception.TypeOf()); Assert.That(() => StreamingStatistics.PopulationVariance(data), Throws.Exception.TypeOf()); @@ -134,6 +139,8 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.DoesNotThrow(() => Statistics.Minimum(data)); Assert.DoesNotThrow(() => Statistics.Maximum(data)); Assert.DoesNotThrow(() => Statistics.Mean(data)); + Assert.DoesNotThrow(() => Statistics.HarmonicMean(data)); + Assert.DoesNotThrow(() => Statistics.GeometricMean(data)); Assert.DoesNotThrow(() => Statistics.Median(data)); Assert.DoesNotThrow(() => Statistics.Quantile(data, 0.3)); Assert.DoesNotThrow(() => Statistics.Variance(data));