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

时间:2016-02-22 16:36:36

标签: python pandas

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

我想根据calc_value为数据框中的每一行分配一个百分位数。但是,由于非唯一的bin边缘,使用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      ])

如果bin边缘不是唯一的,我不在乎,我想继续并为每一行分配一个等值百分位0的零值。然后从那里继续,在这种情况下下一个百分位为10

如何忽略此错误并继续?

2 个答案:

答案 0 :(得分:1)

看起来scipy.stats.rankdata完全符合您的要求,包括对领带休息的良好控制

  

方法:str,可选   用于将排名分配给绑定元素的方法。选项包括'average','min','max','dense'和'ordinal'。

如,

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)

(注意我们如何除以DataFrame的长度)。

答案 1 :(得分:0)

我相信pd.qcut()需要一个整数作为第二个arg,这样数据行数/ int也是一个int。所以你要么必须添加空行以便稍后删除它们,要么找到最接近的int:

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