diff --git a/src/Numerics/Statistics/ArrayStatistics.cs b/src/Numerics/Statistics/ArrayStatistics.cs index 628e53ec..76152f3e 100644 --- a/src/Numerics/Statistics/ArrayStatistics.cs +++ b/src/Numerics/Statistics/ArrayStatistics.cs @@ -86,22 +86,6 @@ namespace MathNet.Numerics.Statistics return max; } - /// - /// Returns the order statistic (order 1..N) from the unsorted data array. - /// WARNING: Works inplace and can thus causes the data array to be reordered. - /// - /// Sample array, no sorting is assumed. Will be reordered. - /// One-based order of the statistic, must be between 1 and N (inclusive). - public static double OrderStatisticInplace(double[] data, int order) - { - if (data == null) throw new ArgumentNullException("data"); - if (order < 1 || order > data.Length) return double.NaN; - - if (order == 1) return Minimum(data); - if (order == data.Length) return Maximum(data); - return SelectInplace(data, order - 1); - } - /// /// Estimates the arithmetic sample mean from the unsorted data array. /// Returns NaN if data is empty or any entry is NaN. @@ -187,9 +171,25 @@ namespace MathNet.Numerics.Statistics return Math.Sqrt(PopulationVariance(data)); } + /// + /// Returns the order statistic (order 1..N) from the unsorted data array. + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + /// One-based order of the statistic, must be between 1 and N (inclusive). + public static double OrderStatisticInplace(double[] data, int order) + { + if (data == null) throw new ArgumentNullException("data"); + if (order < 1 || order > data.Length) return double.NaN; + + if (order == 1) return Minimum(data); + if (order == data.Length) return Maximum(data); + return SelectInplace(data, order - 1); + } + /// /// Estimates the median value from the unsorted data array. - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// WARNING: Works inplace and can thus causes the data array to be reordered. /// /// Sample array, no sorting is assumed. Will be reordered. @@ -198,10 +198,73 @@ namespace MathNet.Numerics.Statistics return QuantileInplace(data, 0.5d); } + + /// + /// Estimates the p-Percentile value from the unsorted data array. + /// If a non-integer Percentile is needed, use Quantile instead. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + /// Percentile selector, between 0 and 100 (inclusive). + public static double PercentileInplace(double[] data, int p) + { + return QuantileInplace(data, p / 100d); + } + + /// + /// Estimates the first quartile value from the unsorted data array. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + public static double LowerQuartileInplace(double[] data) + { + return QuantileInplace(data, 0.25d); + } + + /// + /// Estimates the third quartile value from the unsorted data array. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + public static double UpperQuartileInplace(double[] data) + { + return QuantileInplace(data, 0.75d); + } + + /// + /// Estimates the inter-quartile range from the unsorted data array. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + public static double InterquartileRangeInplace(double[] data) + { + return QuantileInplace(data, 0.75d) - QuantileInplace(data, 0.25d); + } + + /// + /// Estimates {min, lower-quantile, median, upper-quantile, max} from the unsorted data array. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// WARNING: Works inplace and can thus causes the data array to be reordered. + /// + /// Sample array, no sorting is assumed. Will be reordered. + public static double[] FiveNumberSummaryInplace(double[] data) + { + if (data == null) throw new ArgumentNullException("data"); + if (data.Length == 0) return new[] { double.NaN, double.NaN, double.NaN, double.NaN, double.NaN }; + + // TODO: Benchmark: is this still faster than sorting the array then using SortedArrayStatistics instead? + return new[] { Minimum(data), QuantileInplace(data, 0.25), QuantileInplace(data, 0.50), QuantileInplace(data, 0.75), Maximum(data) }; + } + /// /// Estimates the tau-th quantile from the unsorted data array. /// The tau-th quantile is the data value where the cumulative distribution - /// function crosses tau. Applies a linear interpolation, compatible with R-8. + /// function crosses tau. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// WARNING: Works inplace and can thus causes the data array to be reordered. /// /// Sample array, no sorting is assumed. Will be reordered. diff --git a/src/Numerics/Statistics/SortedArrayStatistics.cs b/src/Numerics/Statistics/SortedArrayStatistics.cs index 7061ab8e..812b37b6 100644 --- a/src/Numerics/Statistics/SortedArrayStatistics.cs +++ b/src/Numerics/Statistics/SortedArrayStatistics.cs @@ -79,7 +79,7 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the median value from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. public static double Median(double[] data) @@ -89,8 +89,8 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the p-Percentile value from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. /// If a non-integer Percentile is needed, use Quantile instead. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. /// Percentile selector, between 0 and 100 (inclusive). @@ -101,7 +101,7 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the first quartile value from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. public static double LowerQuartile(double[] data) @@ -111,7 +111,7 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the third quartile value from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. public static double UpperQuartile(double[] data) @@ -121,7 +121,7 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the inter-quartile range from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. public static double InterquartileRange(double[] data) @@ -131,7 +131,7 @@ namespace MathNet.Numerics.Statistics /// /// Estimates {min, lower-quantile, median, upper-quantile, max} from the sorted data array (ascending). - /// Applies a linear interpolation, consistent with Quantile and R-8. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. public static double[] FiveNumberSummary(double[] data) @@ -144,7 +144,8 @@ namespace MathNet.Numerics.Statistics /// /// Estimates the tau-th quantile from the sorted data array (ascending). /// The tau-th quantile is the data value where the cumulative distribution - /// function crosses tau. Applies a linear interpolation, compatible with R-8. + /// function crosses tau. + /// Approximately median-unbiased regardless of the sample distribution (R8). /// /// Sample array, must be sorted ascendingly. /// Quantile selector, between 0.0 and 1.0 (inclusive). diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index f1a41fed..d8e7405f 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -207,10 +207,9 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample median. + /// Estimates the sample median from the provided samples (R8). /// - /// The data to calculate the median of. - /// The median of the sample. + /// The data sample sequence. public static double Median(this IEnumerable data) { if (data == null) throw new ArgumentNullException("data"); @@ -219,10 +218,9 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample median. + /// Estimates the sample median from the provided samples (R8). /// - /// The data to calculate the median of. - /// The median of the sample. + /// The data sample sequence. public static double Median(this IEnumerable data) { if (data == null) throw new ArgumentNullException("data"); @@ -231,11 +229,13 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample tau-quantile. + /// 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 to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. public static double Quantile(this IEnumerable data, double tau) { if (data == null) throw new ArgumentNullException("data"); @@ -244,11 +244,13 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample tau-quantile. + /// 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 to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. public static double Quantile(this IEnumerable data, double tau) { if (data == null) throw new ArgumentNullException("data"); @@ -257,11 +259,10 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the empiric inverse CDF at tau (tau-quantile). + /// Estimates the empiric inverse CDF at tau from the provided samples. /// - /// The data to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. public static double InverseCDF(this IEnumerable data, double tau) { if (data == null) throw new ArgumentNullException("data"); @@ -270,11 +271,10 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the empiric inverse CDF at tau (tau-quantile). + /// Estimates the empiric inverse CDF at tau from the provided samples. /// - /// The data to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. public static double InverseCDF(this IEnumerable data, double tau) { if (data == null) throw new ArgumentNullException("data"); @@ -283,11 +283,13 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample tau-quantile. + /// 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 to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. /// Quantile definition, to choose what product/definition it should be consistent with public static double QuantileCustom(this IEnumerable data, double tau, QuantileDefinition definition) { @@ -297,11 +299,13 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the sample tau-quantile. + /// 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 to calculate the median of. + /// The data sample sequence. /// Quantile selector, between 0.0 and 1.0 (inclusive). - /// The median of the sample. /// Quantile definition, to choose what product/definition it should be consistent with public static double QuantileCustom(this IEnumerable data, double tau, QuantileDefinition definition) { @@ -311,11 +315,134 @@ namespace MathNet.Numerics.Statistics } /// - /// Returns the i-order (1..N) statistic of the provided samples. + /// 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 sample data. - /// Order of the statistic to evaluate. - /// The i'th order statistic in the sample data. + /// The data sample sequence. + /// Percentile selector, between 0 and 100 (inclusive). + public static double Percentile(this IEnumerable data, int p) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + 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. + /// Percentile selector, between 0 and 100 (inclusive). + public static double Percentile(this IEnumerable data, int p) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + return ArrayStatistics.PercentileInplace(array, p); + } + + /// + /// Estimates the first quartile value from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double LowerQuartile(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + return ArrayStatistics.LowerQuartileInplace(array); + } + + /// + /// Estimates the first quartile value from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double LowerQuartile(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + return ArrayStatistics.LowerQuartileInplace(array); + } + + /// + /// Estimates the third quartile value from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double UpperQuartile(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + return ArrayStatistics.UpperQuartileInplace(array); + } + + /// + /// Estimates the third quartile value from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double UpperQuartile(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + return ArrayStatistics.UpperQuartileInplace(array); + } + + /// + /// Estimates the inter-quartile range from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double InterquartileRange(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + return ArrayStatistics.InterquartileRangeInplace(array); + } + + /// + /// Estimates the inter-quartile range from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double InterquartileRange(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + return ArrayStatistics.InterquartileRangeInplace(array); + } + + /// + /// Estimates {min, lower-quantile, median, upper-quantile, max} from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double[] FiveNumberSummary(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.ToArray(); + return ArrayStatistics.FiveNumberSummaryInplace(array); + } + + /// + /// Estimates {min, lower-quantile, median, upper-quantile, max} from the provided samples. + /// Approximately median-unbiased regardless of the sample distribution (R8). + /// + /// The data sample sequence. + public static double[] FiveNumberSummary(this IEnumerable data) + { + if (data == null) throw new ArgumentNullException("data"); + var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); + return ArrayStatistics.FiveNumberSummaryInplace(array); + } + + /// + /// Returns the order statistic (order 1..N) from the provided samples. + /// + /// The data sample sequence. + /// One-based order of the statistic, must be between 1 and N (inclusive). public static double OrderStatistic(IEnumerable data, int order) { if (data == null) throw new ArgumentNullException("data");