获取对应给定值的分位数的NumPy函数。

13

我看到很多像这样的问题(问题)是关于R的,但我找不到一个专门用于Python的,并且最好使用numpy。

假设我有一个存储在x中的观测值数组。我可以获取累积了人口q * 100百分比的值。

# Import numpy
import numpy as np

# Get 75th percentile
np.quantile(a=x, q=0.75)

不过,我想知道是否有一个函数可以实现相反的操作。也就是说,一个numpy函数可以输入一个值并返回q

更进一步地说,scipy分布对象具有ppf方法,可以让我做到这一点。我正在寻找类似于numpy的东西。它是否存在?


1
你不能像 (a<value).mean() 这样简单地做吗? - loopy walt
那实际上会非常高效。你想把它作为答案发布吗? - Arturo Sbr
4个回答

16

不是现成的函数,而是一个紧凑且相当快速的代码片段:

(a<value).mean()

你可以(至少在我的计算机上)通过使用np.count_nonzero来挤出几个百分点的更好性能。

np.count_nonzero(a<value) / a.size

但说实话,我甚至都不想费心。


1
这恰好是 scipy.stats.percentileofscorestrict 模式在其源代码中所做的:np.count_nonzero(a < score) / n * 100weak 模式只是用 <= 替换了 <。我进行了一个快速的 %timeit 测试,看起来这比 (a<value).mean() 选项更快。 - BatWannaBe
谢谢,这个有用的问题的答案竟然很难找到。 - Markus
太好了!@loopywalt,你能解释一下你的思考过程吗?它当然有效,但我很难抽象地理解为什么。谢谢! - Tim

9

有一个方便的函数可以做到这一点。请注意,它不是精确的反函数,因为quantile/percentile 函数不是精确的。给定一组有限观察值,百分位数将具有离散值;换句话说,您可能会指定一个介于这些值之间的q ,而函数找到最接近的一个。

from scipy import stats
import numpy as np

stats.percentileofscore(np.arange(0,1,0.12), .65, 'weak') / 100

非常整洁的发现。 - Mad Physicist
实际上,scipy.stats.scoreatpercentile计划被弃用,以更快的numpy.percentile取而代之。不知道为什么他们没有对反向的scipy.stats.percentileofscore采取类似的措施。 - BatWannaBe
考虑到numpy没有相应的替代品,我严重怀疑它会被弃用。 - Mad Physicist

2
如果x是有序的,那么在索引i处的值就是i / len(x)的百分位数(或者根据如何处理边界条件而定)。如果x没有排序,你可以通过将i替换为x.argsort().argsort()[i](或者先对x进行排序)来获得相同的值。由于argsort是其自身的反函数,所以双重argsort告诉你原始元素在排序数组中的位置。
如果你想查找不一定在x中的任意值的结果,你可以对x的排序版本应用np.searchsorted并在结果上进行插值。你也可以使用更复杂的方法,如对排序数据拟合样条曲线或类似方法。

0

vals = x.argsort().argsort()/(x.size-1)在完全唯一值的数组中有效,但如果您有重复值,则会失败。相同的值应该具有相同的分位数值,但是例如,如果数组x有200个零值和800个大于零的值,则此方法将为这些零值提供200个不同的分位数值。更安全的做法是使用vals = np.array([np.count_nonzero(x<x_i)/(x.size-1) for x_i in x]),因为相同的值会获得相同的分位位置。

import numpy as np

def get_quant(x):
  " for each value in x, return which quantile it corresponds to "
  return np.array([np.count_nonzero(x<x_i)/(len(x)-1) for x_i in x])

注意: (x.size-1) 分母确保分位数值从0到1(包括1)的范围内。如果省略 -1,则永远无法达到100%的分位数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接