我正在编写一些代码,我想知道我是否正确计算了排序数组中的百分位数。目前,如果我想计算第 90 个百分位数,我会这样做:ARR[(9 * (N + 1((/10]。或者,假设我正在计算排序数组中的第 50 个百分位数,我这样做:ARR[(5 * (N + 1((/10]。更一般地说,为了计算第 x 个百分位数,我检查索引 [x/100 * (N + 1(],其中 N 是数组的大小。
这些似乎正在工作,但我只是在想是否有某种我错过的边缘情况。 例如,假设您只有 5 个元素。那么第 90 个百分位数应该是多少?它应该只是最大值吗?
提前致谢
例如,假设您只有 5 个元素。那么第 90 个百分位数应该是多少?它应该只是最大值吗?
是的。如果你按照这样的定义(这个只是从维基百科复制的(
N 个有序值列表的第 P 个百分位数(从最小到最大排序(是列表中的最小值,使得不超过 P %的数据严格小于该值,并且至少 P %的数据小于或等于该值
第 5 个元素可以是第 90 个百分位数:
- 不超过 P %的数据严格小于值:80% 的数据严格小于最大元素,即不超过 90% 至少 P %的数据小于或等于
- 该值:100% 的数据小于或等于第 5 个元素,即至少 90%
第 5 个元素是可以做到这一点的最小元素(即使第 4 个和第 5 个元素相等,第 5 个元素仍然是最小的元素,因为百分位数是关于值的,而不是位置(。
对于微调公式,边界情况更有趣 - 例如 5 元素列表的第 79-80-81 个百分位数
element index: 0 1 2 3 4
strictly less: 0% 20% 40% 60% 80%
less or equal: 20% 40% 60% 80% 100%
第 79 个百分位数:预计第 4 个百分位数(60%<79%,79%<=80%( 第 80 个百分位数:预计第 4 个(60%<80%,80%<=80%( 第 81 个百分位数:预计第 5 个(80%<81%,81%<=100%(
这感觉就像向上舍入某些东西(分数指数((知道 80 是边界并查看映射 79->3、80->3 但 81->4(。该函数通常被称为类似ceil()
,Math.ceil()
(问题指定目前没有编程语言(
P 5*P/100 ceil(5*P/100) (5=N)
79 3.95 4
80 4 4
81 4.05 5
((N+1)
会产生 4.74、4.8、4.86,所以可以肯定地说不需要+1
(
因此ceil(N*P/100)
似乎真的是那个(当然它也在维基百科上,仅比定义低 2-3 行(
请注意,编程语言可能会添加各种怪癖:
- 数组/列表通常从 0 开始索引
ceil()
的结果可能需要转换为整数- 还有一个偷偷摸摸的:如果
N
和P
是整数,您可能需要确保除法不是整数除法(自动丢弃分数部分,因此向下舍入结果(。
Java 行是这样的
int index=(int)Math.ceil(N*P/100.0)-1;
如果你想要第 0 个百分位数,它可以单独处理,或者与max()
一起被黑到同一行
public static int percentile(int array[],float P) {
return array[Math.max(0,
Math.min(array.length, (int)Math.ceil(array.length*P/100))-1)];
}
(这个也使用min()
,并且会为任何有限P
产生一些结果,隐式地将其截断到 0<=P<=100 范围(