鉴于一系列延迟(以毫秒为单位),我想从中计算百分位数。我得到了下面的工作方法,但我不知道如何验证这是否能给我准确的结果?
public static long[] percentiles(long[] latencies, double... percentiles) {
Arrays.sort(latencies, 0, latencies.length);
long[] values = new long[percentiles.length];
for (int i = 0; i < percentiles.length; i++) {
int index = (int) (percentiles[i] * latencies.length);
values[i] = latencies[index];
}
return values;
}
我想从latencies
数组获得第50,95,99和99.9百分位数。
long[] percs = percentiles(latencies, 0.5, 0.95, 0.99, 0.999);
考虑到长时间的延迟,这是获得百分位数的正确方法吗?我正在使用Java 7。
答案 0 :(得分:9)
这就是你要找的东西:
class Program
{
static void Main(string[] args)
{
List<long> latencies = new List<long>() { 3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20 };
Console.WriteLine(Percentile(latencies,25));
Console.WriteLine(Percentile(latencies, 50));
Console.WriteLine(Percentile(latencies, 75));
Console.WriteLine(Percentile(latencies, 100));
Console.ReadLine();
}
public static long Percentile(List<long> latencies, double Percentile)
{
latencies.Sort();
int Index = (int)Math.Ceiling(((double)Percentile / (double)100) * (double)latencies.Count);
return latencies[Index-1];
}
}
答案 1 :(得分:2)
public static double percentile(double percentile, List<Double> items) {
Preconditions.checkArgument(percentile >= 0);
Preconditions.checkArgument(percentile <= 100);
Preconditions.checkArgument(!items.isEmpty());
Collections.sort(items);
return items.get((int) Math.round(percentile / 100.0 * (items.size() - 1)));
}
@Test
public void test1() {
List<Double> list = Arrays.asList(0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
assertThat(percentile(0, list)).isEqualTo(0.0);
assertThat(percentile(20, list)).isEqualTo(2.0);
assertThat(percentile(80, list)).isEqualTo(8.0);
assertThat(percentile(100, list)).isEqualTo(10.0);
}
@Test
public void test2() {
List<Double> list = Arrays.asList(0.0, 1.0, 2.0, 3.0);
assertThat(percentile(51, list)).isEqualTo(2.0);
assertThat(percentile(49, list)).isEqualTo(1.0);
}
@Test
public void test3() {
List<Double> list = Arrays.asList(42.0);
assertThat(percentile(0, list)).isEqualTo(42.0);
assertThat(percentile(100, list)).isEqualTo(42.0);
}
答案 2 :(得分:1)
根据Wikipedia,没有百分位数的标准定义;但是,它们给出了一些可能的定义。您发布的代码似乎最接近最近等级方法,但它并不完全相同。
他们给出的公式是
n = ceiling((P / 100) x N)
其中N
是列表的长度,P
是百分位数,n
将是序数排名。你已经完成了除以100的除法。看看它们给出的例子,很明显“序数等级”是列表中的索引,但它是1 - 相对的。因此,要获得Java数组的索引,您必须减去1.因此,正确的公式应该是
n = ceiling(percentile * N) - 1
使用代码中的变量,Java等价物将是
(int) Math.ceil(percentiles[i] * latencies.length) - 1
这不是你写的代码。当您将double
转换为int
时,结果将舍入为0,即它相当于“floor”函数。所以你的代码计算
floor(percentiles[i] * latencies.length)
如果percentiles[i] * latencies.length
不是整数,则结果都是相同的。但是,如果它是一个整数,那么“floor”和“ceiling”是相同的值,那么结果将是不同的。
维基百科的一个例子是当列表为{15,20,35,40,50}时计算第40个百分点。他们的答案是找到列表中的第二项,即20,因为0.40 * 5 = 2.0,而ceiling(2.0)= 2.0。
但是,您的代码:
int index = (int) (percentiles[i] * latencies.length);
将导致index
为2,这不是您想要的,因为这将为您提供列表中的第三项,而不是第二项。
因此,为了匹配Wikipedia定义,您需要稍微修改索引的计算。 (另一方面,如果有人出现并且说你的计算是正确的并且维基百科错了,我也不会感到惊讶。我们会看到......)