diff --git a/src/Numerics/ExcelFunctions.cs b/src/Numerics/ExcelFunctions.cs index 53763368..6904b6e0 100644 --- a/src/Numerics/ExcelFunctions.cs +++ b/src/Numerics/ExcelFunctions.cs @@ -33,6 +33,7 @@ using MathNet.Numerics.Distributions; using MathNet.Numerics.Statistics; // ReSharper disable InconsistentNaming + namespace MathNet.Numerics { /// @@ -85,6 +86,12 @@ namespace MathNet.Numerics throw new ArgumentOutOfRangeException("quant"); } } + + public static double PERCENTRANK(double[] array, double x) + { + return array.QuantileRank(x, RankDefinition.Min); + } } } + // ReSharper restore InconsistentNaming diff --git a/src/Numerics/Statistics/RankDefinition.cs b/src/Numerics/Statistics/RankDefinition.cs index a34e3825..063a24cd 100644 --- a/src/Numerics/Statistics/RankDefinition.cs +++ b/src/Numerics/Statistics/RankDefinition.cs @@ -44,6 +44,8 @@ namespace MathNet.Numerics.Statistics Max = 3, /// Permutation with increasing values at each index of ties. - First = 4 + First = 4, + + EmpiricalCDF = 5 } -} +} \ No newline at end of file diff --git a/src/Numerics/Statistics/SortedArrayStatistics.cs b/src/Numerics/Statistics/SortedArrayStatistics.cs index 95397227..f00e1244 100644 --- a/src/Numerics/Statistics/SortedArrayStatistics.cs +++ b/src/Numerics/Statistics/SortedArrayStatistics.cs @@ -282,6 +282,89 @@ namespace MathNet.Numerics.Statistics } } + /// + /// Estimates the empirical cummulative distribution function (CDF) at x from the sorted data array (ascending). + /// + /// The data sample sequence. + /// The value where to estimate the CDF at. + public static double EmpiricalCDF(double[] data, double x) + { + if (x < data[0]) return 0.0; + if (x >= data[data.Length - 1]) return 1.0; + + int right = Array.BinarySearch(data, x); + if (right >= 0) + { + while (right < data.Length - 1 && data[right + 1] == data[right]) + { + right++; + } + return (right + 1)/(double)(data.Length); + } + + return (~right)/(double)(data.Length); + } + + /// + /// Estimates the quantile tau from the sorted data array (ascending). + /// 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 value. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with + public static double QuantileRank(double[] data, double x, RankDefinition definition = RankDefinition.Default) + { + if (x < data[0]) return 0.0; + if (x >= data[data.Length - 1]) return 1.0; + + int right = Array.BinarySearch(data, x); + if (right >= 0) + { + int left = right; + while (left > 0 && data[left - 1] == data[left]) + { + left--; + } + while (right < data.Length - 1 && data[right + 1] == data[right]) + { + right++; + } + + switch (definition) + { + case RankDefinition.EmpiricalCDF: + return (right + 1)/(double)(data.Length); + case RankDefinition.Max: + return right/(double)(data.Length - 1); + case RankDefinition.Min: + return left/(double)(data.Length - 1); + case RankDefinition.Average: + return (left/(double)(data.Length - 1) + right/(double)(data.Length - 1))/2; + default: + throw new NotSupportedException(); + } + } + else + { + right = ~right; + int left = right - 1; + + switch (definition) + { + case RankDefinition.EmpiricalCDF: + return (left + 1)/(double)(data.Length); + default: + { + var a = left/(double)(data.Length - 1); + var b = right/(double)(data.Length - 1); + return ((data[right] - x)*a + (x - data[left])*b)/(data[right] - data[left]); + } + } + } + } + /// /// Evaluates the rank of each entry of the sorted data array (ascending). /// The rank definition can be specificed to be compatible diff --git a/src/Numerics/Statistics/Statistics.cs b/src/Numerics/Statistics/Statistics.cs index b10c0c13..d752ff5b 100644 --- a/src/Numerics/Statistics/Statistics.cs +++ b/src/Numerics/Statistics/Statistics.cs @@ -370,51 +370,7 @@ namespace MathNet.Numerics.Statistics } /// - /// Estimates the empirical inverse CDF at tau from the provided samples. - /// - /// The data sample sequence. - /// Quantile selector, between 0.0 and 1.0 (inclusive). - public static double InverseCDF(this IEnumerable data, double tau) - { - var array = data.ToArray(); - return ArrayStatistics.QuantileCustomInplace(array, tau, QuantileDefinition.InverseCDF); - } - - /// - /// Estimates the empirical inverse CDF at tau from the provided samples. - /// - /// The data sample sequence. - /// Quantile selector, between 0.0 and 1.0 (inclusive). - public static double InverseCDF(this IEnumerable data, double tau) - { - var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); - return ArrayStatistics.QuantileCustomInplace(array, tau, QuantileDefinition.InverseCDF); - } - - /// - /// Estimates the empirical inverse CDF at tau from the provided samples. - /// - /// The data sample sequence. - public static Func InverseCDFFunc(this IEnumerable data) - { - var array = data.ToArray(); - Array.Sort(array); - return tau => SortedArrayStatistics.QuantileCustom(array, tau, QuantileDefinition.InverseCDF); - } - - /// - /// Estimates the empirical inverse CDF at tau from the provided samples. - /// - /// The data sample sequence. - public static Func InverseCDFFunc(this IEnumerable 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. + /// Estimates 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. @@ -429,7 +385,7 @@ namespace MathNet.Numerics.Statistics } /// - /// stimates the tau-th quantile from the provided samples. + /// Estimates 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. @@ -444,7 +400,7 @@ namespace MathNet.Numerics.Statistics } /// - /// stimates the tau-th quantile from the provided samples. + /// Estimates 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. @@ -459,7 +415,7 @@ namespace MathNet.Numerics.Statistics } /// - /// stimates the tau-th quantile from the provided samples. + /// Estimates 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. @@ -635,13 +591,14 @@ namespace MathNet.Numerics.Statistics return order => SortedArrayStatistics.OrderStatistic(array, order); } + /// /// Evaluates the rank of each entry of the provided samples. /// The rank definition can be specificed to be compatible /// with an existing system. /// /// The data sample sequence. - /// Rank definition, to choose how ties should be handled. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with public static double[] Ranks(this IEnumerable data, RankDefinition definition = RankDefinition.Default) { var array = data.ToArray(); @@ -654,11 +611,154 @@ namespace MathNet.Numerics.Statistics /// with an existing system. /// /// The data sample sequence. - /// Rank definition, to choose how ties should be handled. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with public static double[] Ranks(this IEnumerable data, RankDefinition definition = RankDefinition.Default) { - var array = data.Where(d => d.HasValue).Select(d => d.Value).ToArray(); - return ArrayStatistics.RanksInplace(array, definition); + return Ranks(data.Where(d => d.HasValue).Select(d => d.Value), definition); + } + + + /// + /// Estimates the quantile tau 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 value. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with + public static double QuantileRank(this IEnumerable data, double x, RankDefinition definition = RankDefinition.Default) + { + var array = data.ToArray(); + Array.Sort(array); + return SortedArrayStatistics.QuantileRank(array, x, definition); + } + + /// + /// Estimates the quantile tau 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 value. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with + public static double QuantileRank(this IEnumerable data, double x, RankDefinition definition = RankDefinition.Default) + { + return QuantileRank(data.Where(d => d.HasValue).Select(d => d.Value), x, definition); + } + + /// + /// Estimates the quantile tau 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. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with + public static Func QuantileRankFunc(this IEnumerable data, RankDefinition definition = RankDefinition.Default) + { + var array = data.ToArray(); + Array.Sort(array); + return x => SortedArrayStatistics.QuantileRank(array, x, definition); + } + + /// + /// Estimates the quantile tau 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. + /// Rank definition, to choose how ties should be handled and what product/definition it should be consistent with + public static Func QuantileRankFunc(this IEnumerable data, RankDefinition definition = RankDefinition.Default) + { + return QuantileRankFunc(data.Where(d => d.HasValue).Select(d => d.Value), definition); + } + + + /// + /// Estimates the empirical cummulative distribution function (CDF) at x from the provided samples. + /// + /// The data sample sequence. + /// The value where to estimate the CDF at. + public static double EmpiricalCDF(this IEnumerable data, double x) + { + var array = data.ToArray(); + Array.Sort(array); + return SortedArrayStatistics.EmpiricalCDF(array, x); + } + + /// + /// Estimates the empirical cummulative distribution function (CDF) at x from the provided samples. + /// + /// The data sample sequence. + /// The value where to estimate the CDF at. + public static double EmpiricalCDF(this IEnumerable data, double x) + { + return EmpiricalCDF(data.Where(d => d.HasValue).Select(d => d.Value), x); + } + + /// + /// Estimates the empirical cummulative distribution function (CDF) at x from the provided samples. + /// + /// The data sample sequence. + public static Func EmpiricalCDFFunc(this IEnumerable data) + { + var array = data.ToArray(); + Array.Sort(array); + return x => SortedArrayStatistics.EmpiricalCDF(array, x); + } + + /// + /// Estimates the empirical cummulative distribution function (CDF) at x from the provided samples. + /// + /// The data sample sequence. + public static Func EmpiricalCDFFunc(this IEnumerable data) + { + return EmpiricalCDFFunc(data.Where(d => d.HasValue).Select(d => d.Value)); + } + + + /// + /// Estimates the empirical inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + /// Quantile selector, between 0.0 and 1.0 (inclusive). + public static double InverseCDF(this IEnumerable data, double tau) + { + var array = data.ToArray(); + return ArrayStatistics.QuantileCustomInplace(array, tau, QuantileDefinition.InverseCDF); + } + + /// + /// Estimates the empirical inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + /// Quantile selector, between 0.0 and 1.0 (inclusive). + public static double InverseCDF(this IEnumerable data, double tau) + { + return InverseCDF(data.Where(d => d.HasValue).Select(d => d.Value), tau); + } + + /// + /// Estimates the empirical inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + public static Func InverseCDFFunc(this IEnumerable data) + { + var array = data.ToArray(); + Array.Sort(array); + return tau => SortedArrayStatistics.QuantileCustom(array, tau, QuantileDefinition.InverseCDF); + } + + /// + /// Estimates the empirical inverse CDF at tau from the provided samples. + /// + /// The data sample sequence. + public static Func InverseCDFFunc(this IEnumerable data) + { + return InverseCDFFunc(data.Where(d => d.HasValue).Select(d => d.Value)); } } } diff --git a/src/UnitTests/ExcelTests.cs b/src/UnitTests/ExcelTests.cs index 1280a5b8..73efe30a 100644 --- a/src/UnitTests/ExcelTests.cs +++ b/src/UnitTests/ExcelTests.cs @@ -102,6 +102,38 @@ namespace MathNet.Numerics.UnitTests Assert.That(ExcelFunctions.QUARTILE(array, 3), Is.EqualTo(9.25000000000).Within(1e-8)); Assert.That(ExcelFunctions.QUARTILE(array, 4), Is.EqualTo(12.00000000000).Within(1e-8)); } + + [Test] + public void PERCENTRANK() + { + var array = new Double[] { 1, 8, 12, 7, 2, 9, 10, 4 }; + Assert.That(ExcelFunctions.PERCENTRANK(array, 1.0), Is.EqualTo(0.00000000000).Within(1e-8), "A1"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 2.0), Is.EqualTo(0.14285714280).Within(1e-8), "A2"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 3.0), Is.EqualTo(0.21428571420).Within(1e-8), "A3"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 4.0), Is.EqualTo(0.28571428570).Within(1e-8), "A4"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 5.0), Is.EqualTo(0.33333333330).Within(1e-8), "A5"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 6.0), Is.EqualTo(0.38095238090).Within(1e-8), "A6"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 7.0), Is.EqualTo(0.42857142850).Within(1e-8), "A7"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 8.0), Is.EqualTo(0.57142857140).Within(1e-8), "A8"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 9.0), Is.EqualTo(0.71428571420).Within(1e-8), "A9"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 10.0), Is.EqualTo(0.85714285710).Within(1e-8), "A10"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 11.0), Is.EqualTo(0.92857142850).Within(1e-8), "A11"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 12.0), Is.EqualTo(1.00000000000).Within(1e-8), "A12"); + + array = new Double[] { 1, 9, 12, 7, 2, 9, 10, 2 }; + Assert.That(ExcelFunctions.PERCENTRANK(array, 1.0), Is.EqualTo(0.00000000000).Within(1e-8), "B1"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 2.0), Is.EqualTo(0.14285714280).Within(1e-8), "B2"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 3.0), Is.EqualTo(0.31428571420).Within(1e-8), "B3"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 4.0), Is.EqualTo(0.34285714280).Within(1e-8), "B4"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 5.0), Is.EqualTo(0.37142857140).Within(1e-8), "B5"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 6.0), Is.EqualTo(0.40000000000).Within(1e-8), "B6"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 7.0), Is.EqualTo(0.42857142850).Within(1e-8), "B7"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 8.0), Is.EqualTo(0.50000000000).Within(1e-8), "B8"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 9.0), Is.EqualTo(0.57142857140).Within(1e-8), "B9"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 10.0), Is.EqualTo(0.85714285710).Within(1e-8), "B10"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 11.0), Is.EqualTo(0.92857142850).Within(1e-8), "B11"); + Assert.That(ExcelFunctions.PERCENTRANK(array, 12.0), Is.EqualTo(1.00000000000).Within(1e-8), "B12"); + } } } // ReSharper restore InconsistentNaming diff --git a/src/UnitTests/StatisticsTests/StatisticsTests.cs b/src/UnitTests/StatisticsTests/StatisticsTests.cs index 725d8f4e..16837ca8 100644 --- a/src/UnitTests/StatisticsTests/StatisticsTests.cs +++ b/src/UnitTests/StatisticsTests/StatisticsTests.cs @@ -65,7 +65,6 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests { double[] data = null; - // ReSharper disable InvokeAsExtensionMethod Assert.That(() => Statistics.Minimum(data), Throws.Exception); Assert.That(() => Statistics.Maximum(data), Throws.Exception); Assert.That(() => Statistics.Mean(data), Throws.Exception); @@ -77,7 +76,6 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Assert.That(() => Statistics.PopulationStandardDeviation(data), Throws.Exception); Assert.That(() => Statistics.Covariance(data, data), Throws.Exception); Assert.That(() => Statistics.PopulationCovariance(data, data), Throws.Exception); - // ReSharper restore InvokeAsExtensionMethod Assert.That(() => SortedArrayStatistics.Minimum(data), Throws.Exception.TypeOf()); Assert.That(() => SortedArrayStatistics.Minimum(data), Throws.Exception.TypeOf()); @@ -659,6 +657,69 @@ namespace MathNet.Numerics.UnitTests.StatisticsTests Is.EqualTo(new[] { 1.0, 5, 8, 4, 2, 6, 7, 3 }).AsCollection.Within(1e-8)); } + [Test] + public void EmpiricalCDF() + { + // R: ecdf(data)(x) + var ties = new double[] { 1, 9, 12, 7, 2, 9, 10, 2 }; + + Assert.That(Statistics.EmpiricalCDF(ties, -1.0), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 0.0), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 1.0), Is.EqualTo(0.125).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 2.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 3.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 4.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 5.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 6.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 7.0), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 8.0), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 9.0), Is.EqualTo(0.75).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 10.0), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 11.0), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 12.0), Is.EqualTo(1.0).Within(1e-8)); + Assert.That(Statistics.EmpiricalCDF(ties, 13.0), Is.EqualTo(1.0).Within(1e-8)); + } + + [Test] + public void EmpiricalCDFSortedArray() + { + // R: ecdf(data)(x) + var ties = new double[] { 1, 9, 12, 7, 2, 9, 10, 2 }; + Array.Sort(ties); + + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, -1.0), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 0.0), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 1.0), Is.EqualTo(0.125).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 2.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 3.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 4.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 5.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 6.0), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 7.0), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 8.0), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 9.0), Is.EqualTo(0.75).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 10.0), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 11.0), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 12.0), Is.EqualTo(1.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.EmpiricalCDF(ties, 13.0), Is.EqualTo(1.0).Within(1e-8)); + + Assert.That(SortedArrayStatistics.QuantileRank(ties, -1.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 0.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 1.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.125).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 2.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 3.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 4.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 5.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 6.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.375).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 7.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 8.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.5).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 9.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.75).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 10.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 11.0, RankDefinition.EmpiricalCDF), Is.EqualTo(0.875).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 12.0, RankDefinition.EmpiricalCDF), Is.EqualTo(1.0).Within(1e-8)); + Assert.That(SortedArrayStatistics.QuantileRank(ties, 13.0, RankDefinition.EmpiricalCDF), Is.EqualTo(1.0).Within(1e-8)); + } + [Test] public void MedianOnShortSequence() {