pandas:按行计算百分位数并优雅地处理非唯一值



我有一个大约 1000 行的数据帧和一个名为 calc_value 的列。大约 10% 的calc_value值为 0。

我想根据calc_value为数据帧中的每一行分配一个百分位数。但是,由于不唯一的箱边缘,使用 qcut 会给我一个错误:

df['percentile'] = pd.qcut(df.calc_value, 100, labels=False)

它会抛出此错误:

 ValueError: Bin edges must be unique: array([ 0.        ,  0.        ,  0.        ,  0.        ,  0.        ,
    0.        ,  0.        ,  0.        ,  0.        ,  0.00182298,
    0.0030689 ,  0.00394358,  0.00479595,  0.00547278,  0.0060241 ,
    0.0066023 ,  0.00712708,  0.00760456,  0.00816327,  0.00862069,
    0.00917431,  0.00959605,  0.01010101,  0.01058201,  0.01094173,
    0.01136364,  0.01185771,  0.01230635,  0.01282051,  0.01324503,
    0.01369863,  0.0140051 ,  0.01447252,  0.01489758,  0.01528912,
    0.01569299,  0.01612903,  0.01657785,  0.01699717,  0.01750547,
    0.017924  ,  0.01840491,  0.01889004,  0.0193326 ,  0.01984022,
    0.0202292 ,  0.02076186,  0.02118433,  0.02173913,  0.02217742,
    0.02265831,  0.0231333 ,  0.02369503,  0.02422837,  0.02482127,
    0.02551955,  0.0260492 ,  0.02659574,  0.02714932,  0.0276922 ,
    0.02816901,  0.02882712,  0.02941176,  0.03020364,  0.0308642 ,
    0.03141361,  0.03209368,  0.03278689,  0.03349899,  0.03433476,
    0.03508136,  0.03571429,  0.03645665,  0.03703704,  0.03768171,
    0.03852266,  0.0392761 ,  0.04021883,  0.04130278,  0.04222222,
    0.04316547,  0.04416658,  0.04528395,  0.04630852,  0.04761905,
    0.04908678,  0.05062638,  0.05230894,  0.05421013,  0.05604617,
    0.05833204,  0.06024096,  0.06314209,  0.06598985,  0.06975211,
    0.07406687,  0.08098836,  0.08905262,  0.10144029,  0.12169944,
    0.48      ])

我不在乎垃圾箱边缘是否唯一,我想继续为每行分配一个相等的百分位数 0 值为零。然后从那里继续,在本例中10下一个百分位数。

如何忽略此错误并继续?

看起来scipy.stats.rankdata完全可以做你想要的,包括对平局的良好控制

方法 : str, 可选 用于为并列元素分配等级的方法。选项是"平均"、"最小"、"最大"、"密集"和"序数"。

例如,

from scipy.stats import rankdata
>>> rankdata([0, 2, 3, 2], method='min')
array([ 1.,  2.,  4.,  2.])

因此,在您的情况下,您可以使用

from scipy.stats import rankdata
df['percentile'] = rankdata(df.calc_value.values, method=<whatever you want>) / len(df)

(请注意我们如何除以数据帧的长度)。

我相信

pd.qcut() 需要一个 interger 编号作为第二个参数,以便数据行数/int 也是一个整数。 因此,您要么必须添加空行以稍后删除它们,要么通过以下方式找到最接近的整数:

div = 100
while True:
    if not 968%div:
        break
    else:
        div -= 1
print div

最新更新