相对于给定的总体,计算百分等级排名。

9

我有一个“参考人群”(比如说,v = np.random.rand(100)),我想为一个给定的组合(比如说,np.array([0.3, 0.5, 0.7]))计算百分位数。

逐个计算很容易:

def percentile_rank(x):
    return (v<x).sum() / len(v)
percentile_rank(0.4)
=> 0.4

实际上,有一个开箱即用的scipy.stats.percentileofscore函数 - 但它不能用于向量。

np.vectorize(percentile_rank)(np.array([0.3, 0.5, 0.7]))
=> [ 0.33  0.48  0.71]

这样做可以得到预期的结果,但我感觉应该有一个内置的方法来实现这个功能。
我也可以作弊:
pd.concat([pd.Series([0.3, 0.5, 0.7]),pd.Series(v)],ignore_index=True).rank(pct=True).loc[0:2]

0    0.330097
1    0.485437
2    0.718447

这种方法有两个问题:

  1. 我不希望测试数据[0.3, 0.5, 0.7]成为排名的一部分。
  2. 我不想浪费时间计算参考人群的排名。

那么,有什么符合惯用法的方法来解决这个问题呢?

4个回答

4

安装:

In [62]: v=np.random.rand(100)

In [63]: x=np.array([0.3, 0.4, 0.7])

使用Numpy广播:

In [64]: (v<x[:,None]).mean(axis=1)
Out[64]: array([ 0.18,  0.28,  0.6 ])

检查:

In [67]: percentile_rank(0.3)
Out[67]: 0.17999999999999999

In [68]: percentile_rank(0.4)
Out[68]: 0.28000000000000003

In [69]: percentile_rank(0.7)
Out[69]: 0.59999999999999998

vx都是数据框中的Series列时,我会得到ValueError: Lengths must match to compare错误。 - sds
1
@sds,在这种情况下,您可以这样做:(v.values<x.values[:,None]).mean(axis=1) - MaxU - stand with Ukraine

2
我认为 pd.cut 可以做到这一点。
s=pd.Series([-np.inf,0.3, 0.5, 0.7])
pd.cut(v,s,right=False).value_counts().cumsum()/len(v)
Out[702]: 
[-inf, 0.3)    0.37
[0.3, 0.5)     0.54
[0.5, 0.7)     0.71
dtype: float64

您的函数返回结果

np.vectorize(percentile_rank)(np.array([0.3, 0.5, 0.7]))
Out[696]: array([0.37, 0.54, 0.71])

这似乎依赖于测试分数已经排好序。如果可能的话,我宁愿避免这种情况。 - sds

2
你可以使用 quantile 函数:
np.random.seed(123)
v=np.random.rand(100)

s = pd.Series(v)
arr = np.array([0.3,0.5,0.7])

s.quantile(arr)

输出:

0.3    0.352177
0.5    0.506130
0.7    0.644875
dtype: float64

1
我认为这是我正在寻找的函数的反函数。 - sds

0

我知道我来晚了,但是想要补充一下,pandas有另一种方法可以通过Series.rank获得你想要的结果。只需使用pct=True选项即可。


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