Python 如何获取numpy/scipy中特定百分位的索引?

Python 如何获取numpy/scipy中特定百分位的索引?,python,numpy,scipy,Python,Numpy,Scipy,我已经了解了如何计算特定百分位数的值,以及如何计算对应于每个元素的百分位数 使用第一个解决方案,我可以计算值并扫描原始数组以找到索引 使用第二种解决方案,我可以扫描整个输出数组以查找我要查找的百分比 但是,如果我想知道与特定百分位相对应的索引(或包含与该索引最接近的元素的索引),这两种方法都需要额外的扫描 是否有更直接或内置的方法来获取对应于百分位的指数 注意:我的数组未排序,我希望索引位于原始未排序数组中,假设数组已排序。。。除非我误解了你,否则你可以通过取数组的长度-1,乘以分位数,四舍

我已经了解了如何计算特定百分位数的值,以及如何计算对应于每个元素的百分位数

  • 使用第一个解决方案,我可以计算值并扫描原始数组以找到索引

  • 使用第二种解决方案,我可以扫描整个输出数组以查找我要查找的百分比

但是,如果我想知道与特定百分位相对应的索引(或包含与该索引最接近的元素的索引),这两种方法都需要额外的扫描

是否有更直接或内置的方法来获取对应于百分位的指数


注意:我的数组未排序,我希望索引位于原始未排序数组中,假设数组已排序。。。除非我误解了你,否则你可以通过取数组的长度-1,乘以分位数,四舍五入到最接近的整数来计算百分位数的指数

round( (len(array) - 1) * (percentile / 100.) )

应该为您提供最接近该百分位的索引

这有点复杂,但您可以使用
np.argpartition
获得所需的内容。让我们简单地排列并洗牌:

>>> a = np.arange(10)
>>> np.random.shuffle(a)
>>> a
array([5, 6, 4, 9, 2, 1, 3, 0, 7, 8])
例如,如果您想查找分位数0.25的索引,这将对应于排序数组的位置
idx
中的项:

>>> idx = 0.25 * (len(a) - 1)
>>> idx
2.25
您需要找出如何将其四舍五入为整数,比如说使用最接近的整数:

>>> idx = int(idx + 0.5)
>>> idx
2
如果现在调用
np.argpartition
,您将得到以下结果:

>>> np.argpartition(a, idx)
array([7, 5, 4, 3, 2, 1, 6, 0, 8, 9], dtype=int64)
>>> np.argpartition(a, idx)[idx]
4
>>> a[np.argpartition(a, idx)[idx]]
2

很容易检查最后两个表达式是否分别是.25分位数的索引和值。

如果要使用numpy,还可以使用内置的百分位数函数。从numpy的1.9.0版开始,percentile具有“插值”选项,允许您选择较低/较高/最近的百分位值。以下内容将用于未排序的数组,并查找最近的百分位索引:

import numpy as np
p=70 # my desired percentile, here 70% 
x=np.random.uniform(10,size=(1000))-5.0  # dummy vector

# index of array entry nearest to percentile value
pcen=np.percentile(x,p,interpolation='nearest')
i_near=abs(x-pcen).argmin()
大多数人通常希望得到上述最接近的百分位值。但仅为了完整性,您还可以轻松指定以获得低于或高于所述百分位值的条目:

# Use this to get index of array entry greater than percentile value:
pcen=np.percentile(x,p,interpolation='higher')

# Use this to get index of array entry smaller than percentile value:
pcen=np.percentile(x,p,interpolation='lower')
对于numpy
# Calculate 70th percentile:
pcen=np.percentile(x,p)
i_high=np.asarray([i-pcen if i-pcen>=0 else x.max()-pcen for i in x]).argmin()
i_low=np.asarray([i-pcen if i-pcen<=0 else x.min()-pcen for i in x]).argmax()
i_near=abs(x-pcen).argmin()
2.3436832738049946

x[i_high]
2.3523077864975441

x[i_low]
2.339987054079617

x[i_near]
i_high,i_low,i_near
2.339987054079617

x[i_near]
i_high,i_low,i_near
(876368368)


i、 e.位置876是最接近的超过pcen的值,但位置368更接近,但略小于百分位值。

您可以使用df.quantile()在指定分位数中选择df中的值


您可以这样使用numpy的
np.百分位数

import numpy as np

percentile = 75
mylist = [random.random() for i in range(100)] # random list

percidx = mylist.index(np.percentile(mylist, percentile, interpolation='nearest'))
使用numpy

arr = [12, 19, 11, 28, 10]
p = 0.75
np.argsort(arr)[int((len(arr) - 1) * p)]

这将根据需要返回11。

我的数组未排序,我希望索引位于原始数组中。我更新了问题以澄清问题。是否对数组进行排序,在最接近分位数*(长度-1)的索引处查找元素
然后在原始数组中查找其索引可以解决问题?通过线性搜索在原始数组中查找索引相当于执行问题中已列出的两个解决方案之一。:)好的,您可以使用索引
枚举
压缩原始元素,按第二个元素排序,然后取分位数*最后一个元素。如果原始数组未排序,我不清楚您是否可以避免至少执行O(n*log(n))工作我已经对此进行了一些测试,正确的公式不是
round((len(array)-1)*(percentile/100.)
而是:
round(len(array)*(percentile/100.))-1
?基本上从末尾的索引中删除1,而不是从长度中删除+1;FWIW,如果
a
不是
argpartion(a,idx)
的混洗,那么您的答案显然是正确的。如果列表中的值重复,这是否有效
y=[0,0,0,2,2,4,5,5,9]
int(0.75*(len(y)-1)+0.5)==6
y[np.argpartition(y,6)[6]
输出5和
y[5]
->4=(关于解决方案
i_近=abs(x,p,interpolation='nearest')i_near=abs(x-y).argmin()
甚至更快一点做
y=np.percentile(x,p,interpolation='nearest')i_near=np.where(x==a).argmin()
谢谢你说得对,我将更新以包括这一点