public static double[] Rank(this double[] samples, bool alreadySorted = false) { int[] idx = Vector.Range(0, samples.Length); if (!alreadySorted) { samples = (double[])samples.Clone(); Array.Sort(samples, idx); } double[] ranks = new double[samples.Length]; double tieSum = 0; int tieSize = 0; int start = 0; while (samples[start] == 0) start++; ranks[start] = 1; for (int i = start + 1, r = 1; i < ranks.Length; i++) { // Check if we have a tie if (samples[i] != samples[i - 1]) { // This is not a tie. // Was a tie before? if (tieSize > 0) { // Yes. Then set the previous // elements with the average. for (int j = 0; j < tieSize + 1; j++) ranks[i - j - 1] = (r + tieSum) / (tieSize + 1); tieSize = 0; tieSum = 0; } ranks[i] = ++r; } else { // This is a tie. Compute how // long we have been in a tie. tieSize++; tieSum += r++; } } if (!alreadySorted) Array.Sort(idx, ranks); return ranks; }
public void RankTest1() { double[] values = { 2, 3, 4, 4, 5, 6, 8, 10, 10, 14, 16, 20, 32, 40 }; double[] expected = { 1, 2, 3.5, 3.5, 5, 6, 7, 8.5, 8.5, 10, 11, 12, 13, 14 }; double[] actual = Tools.Rank(values); Assert.IsTrue(expected.IsEqual(actual)); }