Java 从长数组计算百分位数?

Java 从长数组计算百分位数?,java,math,statistics,apache-commons,percentile,Java,Math,Statistics,Apache Commons,Percentile,给定一个以毫秒为单位的长延迟数组,我想从中计算百分比。我得到了下面的方法来做这项工作,但我不知道如何才能验证这是否给了我准确的结果 public static long[] percentiles(long[] latencies, double... percentiles) { Arrays.sort(latencies, 0, latencies.length); long[] values = new long[percentiles.length]; for

给定一个以毫秒为单位的长延迟数组,我想从中计算百分比。我得到了下面的方法来做这项工作,但我不知道如何才能验证这是否给了我准确的结果

  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;
  }
考虑到长时间的延迟,这是获得百分位数的正确方法吗?我正在使用Java 7。

根据,没有百分位的标准定义;然而,它们给出了一些可能的定义。您发布的代码似乎与最近的秩方法最接近,但并不完全相同

他们给出的公式是

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
不是一个整数,则结果是相同的。但是,如果它是一个整数,因此“地板”和“天花板”是相同的值,则结果将不同

维基百科的一个例子是,当列表为{15,20,35,40,50}时,计算第40个百分位数。他们的答案是找到列表中的第二项,即20,因为0.40*5=2.0,上限(2.0)=2.0

但是,您的代码:

int index = (int) (percentiles[i] * latencies.length);
将导致
index
为2,这不是您想要的,因为这将为您提供列表中的第三项,而不是第二项


因此,为了匹配Wikipedia的定义,需要对索引的计算进行一些修改。(另一方面,如果有人说你的计算是正确的,而维基百科是错误的,我也不会感到惊讶。我们会看到…

这就是你要找的:

public static void main(String[] args) {
    List<Long> latencies = new List<Long>() { 3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20 };

    System.out.println(percentile(latencies,25));
    System.out.println(percentile(latencies, 50));
    System.out.println(percentile(latencies, 75));
    System.out.println(percentile(latencies, 100));
}

public static long percentile(List<Long> latencies, double percentile) {
    Collections.sort(latencies);
    int index = (int) Math.ceil(percentile / 100.0 * latencies.size());
    return latencies.get(index-1);
}
publicstaticvoidmain(字符串[]args){
列表延迟=新列表(){3,6,7,8,8,9,10,13,15,16,20};
系统输出println(百分位数(潜伏期,25));
系统输出println(百分位数(潜伏期,50));
系统输出println(百分位数(潜伏期,75));
系统输出println(百分位数(潜伏期,100));
}
公共静态长百分位(列出延迟,双百分位){
集合。排序(延迟);
int index=(int)Math.ceil(percentile/100.0*latencies.size());
返回延迟。get(索引-1);
}

公共静态双百分位(双百分位,列表项){
前提条件。检查参数(百分位数>=0);

Premissions.checkArgument(percentile Umm,您注意到问题上的Java标记了吗?快速翻译为Java:
公共静态双百分位(列表值,双百分位){Collections.sort(值);int index=(int)Math.ceil((percentile/100)*values.size();返回值.get(index-1);}
当百分位数为0时,它将崩溃,但我猜这是边缘情况。请注意,您的
百分位数方法不仅计算百分位数值(并不总是正确的——请参阅我的答案)然后返回值,它也会对
延迟
数组进行排序,这可能是一个不可取的副作用。这在您试图编写的小程序中可能是无害的,但一般来说,一个方法产生的副作用不是该方法的目的,这不是一个好的做法。
public static void main(String[] args) {
    List<Long> latencies = new List<Long>() { 3, 6, 7, 8, 8, 9, 10, 13, 15, 16, 20 };

    System.out.println(percentile(latencies,25));
    System.out.println(percentile(latencies, 50));
    System.out.println(percentile(latencies, 75));
    System.out.println(percentile(latencies, 100));
}

public static long percentile(List<Long> latencies, double percentile) {
    Collections.sort(latencies);
    int index = (int) Math.ceil(percentile / 100.0 * latencies.size());
    return latencies.get(index-1);
}
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);
}