From b0d8195af019f695ac576c35b9dd314c2f8c5c90 Mon Sep 17 00:00:00 2001 From: Christoph Ruegg Date: Tue, 26 Mar 2013 10:47:26 +0100 Subject: [PATCH] Statistics: Func-variants of quantile, icdf, percentile, orderstat --- src/Numerics/Statistics/Statistics.cs | 127 ++++++++++++++++++ .../StatisticsTests/StatisticsTests.cs | 20 +++ 2 files changed, 147 insertions(+) diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index d8e7405f..b0fd1638 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -258,6 +258,37 @@ namespace MathNet.Numerics.Statistics return ArrayStatistics.QuantileInplace(array, tau); } + /// + /// Estimates the tau-th quantile from the provided samples. + /// The tau-th quantile is the data value where the cumulative distribution + /// function crosses tau. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static Func QuantileFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.Quantile(array, tau); + } + + /// + /// Estimates the tau-th quantile from the provided samples. + /// The tau-th quantile is the data value where the cumulative distribution + /// function crosses tau. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + /// Quantile selector, between 0.0 and 1.0 (inclusive). + public static Func QuantileFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.Quantile(array, tau); + } + /// /// Estimates the empiric inverse CDF at tau from the provided samples. /// @@ -282,6 +313,30 @@ namespace MathNet.Numerics.Statistics return ArrayStatistics.QuantileCustomInplace(array, tau, QuantileDefinition.InverseCDF); } + /// + /// Estimates the empiric inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + public static Func InverseCDFFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.QuantileCustom(array, tau, QuantileDefinition.InverseCDF); + } + + /// + /// Estimates the empiric inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + public static Func InverseCDFFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.QuantileCustom(array, tau, QuantileDefinition.InverseCDF); + } + /// /// stimates the tau-th quantile from the provided samples. /// The tau-th quantile is the data value where the cumulative distribution @@ -314,6 +369,38 @@ namespace MathNet.Numerics.Statistics return ArrayStatistics.QuantileCustomInplace(array, tau, definition); } + /// + /// stimates the tau-th quantile from the provided samples. + /// The tau-th quantile is the data value where the cumulative distribution + /// function crosses tau. The quantile definition can be specificed to be compatible + /// with an existing system. + /// + /// The data sample sequence. + /// Quantile definition, to choose what product/definition it should be consistent with + public static Func QuantileCustomFunc(this IEnumerable data, QuantileDefinition definition) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.QuantileCustom(array, tau, definition); + } + + /// + /// stimates the tau-th quantile from the provided samples. + /// The tau-th quantile is the data value where the cumulative distribution + /// function crosses tau. The quantile definition can be specificed to be compatible + /// with an existing system. + /// + /// The data sample sequence. + /// Quantile definition, to choose what product/definition it should be consistent with + public static Func QuantileCustomFunc(this IEnumerable data, QuantileDefinition definition) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.QuantileCustom(array, tau, definition); + } + /// /// Estimates the p-Percentile value from the provided samples. /// If a non-integer Percentile is needed, use Quantile instead. @@ -342,6 +429,34 @@ namespace MathNet.Numerics.Statistics return ArrayStatistics.PercentileInplace(array, p); } + /// + /// Estimates the p-Percentile value from the provided samples. + /// If a non-integer Percentile is needed, use Quantile instead. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static Func PercentileFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + Array.Sort(array); + return p => SortedArrayStatistics.Percentile(array, p); + } + + /// + /// Estimates the p-Percentile value from the provided samples. + /// If a non-integer Percentile is needed, use Quantile instead. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static Func PercentileFunc(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + Array.Sort(array); + return p => SortedArrayStatistics.Percentile(array, p); + } + /// /// Estimates the first quartile value from the provided samples. /// Approximately median-unbiased regardless of the sample distribution (R8). @@ -449,5 +564,17 @@ namespace MathNet.Numerics.Statistics var array = data.ToArray(); return ArrayStatistics.OrderStatisticInplace(array, order); } + + /// + /// Returns the order statistic (order 1..N) from the provided samples. + /// + /// The data sample sequence. + public static Func OrderStatisticFunc(IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + Array.Sort(array); + return order => SortedArrayStatistics.OrderStatistic(array, order); + } } } diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index f06d468d..82592bef 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -233,6 +233,16 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests // -3 -1 -0.5 0 1 4 5 6 10 var samples = new[] { -1, 5, 0, -3, 10, -0.5, 4, 1, 6 }; + var f = Statistics.OrderStatisticFunc(samples); + Assert.That(f(0), Is.NaN, "Order-0 (bad)"); + Assert.That(f(1), Is.EqualTo(-3), "Order-1"); + Assert.That(f(2), Is.EqualTo(-1), "Order-2"); + Assert.That(f(3), Is.EqualTo(-0.5), "Order-3"); + Assert.That(f(7), Is.EqualTo(5), "Order-7"); + Assert.That(f(8), Is.EqualTo(6), "Order-8"); + Assert.That(f(9), Is.EqualTo(10), "Order-9"); + Assert.That(f(10), Is.NaN, "Order-10 (bad)"); + Assert.That(Statistics.OrderStatistic(samples, 0), Is.NaN, "Order-0 (bad)"); Assert.That(Statistics.OrderStatistic(samples, 1), Is.EqualTo(-3), "Order-1"); Assert.That(Statistics.OrderStatistic(samples, 2), Is.EqualTo(-1), "Order-2"); @@ -279,7 +289,9 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.InverseCDF(samples, tau), 1e-14); + Assert.AreEqual(expected, Statistics.InverseCDFFunc(samples)(tau), 1e-14); Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.InverseCDF), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.InverseCDF)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.InverseCDF), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 0d, 0d, 1d, 0d), 1e-14); @@ -306,6 +318,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R2), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R2)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.InverseCDFAverage), 1e-14); @@ -330,6 +343,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R3), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R3)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Nearest), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 0.5d, 0d, 0d, 0d), 1e-14); @@ -356,6 +370,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R4), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R4)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.California), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 0d, 0d, 0d, 1d), 1e-14); @@ -382,6 +397,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R5), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R5)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Hydrology), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 0.5d, 0d, 0d, 1d), 1e-14); @@ -408,6 +424,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R6), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R6)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Weibull), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 0d, 1d, 0d, 1d), 1e-14); @@ -434,6 +451,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R7), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R7)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Excel), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 1d, -1d, 0d, 1d), 1e-14); @@ -460,6 +478,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.AreEqual(expected, Statistics.Quantile(samples, tau), 1e-14); Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R8), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R8)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileInplace(samples, tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Median), 1e-14); @@ -487,6 +506,7 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests var samples = new[] {-1, 5, 0, -3, 10, -0.5, 4, 0.2, 1, 6}; Assert.AreEqual(expected, Statistics.QuantileCustom(samples, tau, QuantileDefinition.R9), 1e-14); + Assert.AreEqual(expected, Statistics.QuantileCustomFunc(samples, QuantileDefinition.R9)(tau), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, QuantileDefinition.Normal), 1e-14); Assert.AreEqual(expected, ArrayStatistics.QuantileCustomInplace(samples, tau, 3/8d, 1/4d, 0d, 1d), 1e-14);