根据 python 中的百分位数替换列值

Replace column values based on percentiles in python

我已经对一个数据框进行了分组,我希望每组替换某些列中的值(如果它们小于某个百分位数)。 因此,组内所有大于 0.95 个百分点的值都应替换为 0.95 个百分点,所有小于 0.05 个百分点的值都应替换为 0.05 个百分点。
数据框可能如下所示(示例取自 another question): 两组:“一”和“二”

    A           B           C
0   0.719391    0.091693    one
1   0.951499    0.83716     one
2   0.975212    0.224855    one
3   0.80762     0.031284    one
4   0.63319     0.342889    one
5   0.075102    0.899291    one
6   0.502843    0.773424    one
7   0.032285    0.242476    one
8   0.794938    0.607745    one
9   0.620387    0.574222    one
10  0.446639    0.549749    two
11  0.664324    0.134041    two
12  0.622217    0.505057    two
13  0.670338    0.99087     two
14  0.281431    0.016245    two
15  0.675756    0.185967    two
16  0.145147    0.045686    two
17  0.404413    0.191482    two
18  0.94913     0.943509    two
19  0.164642    0.157013    two

此数据框的结果应为:

A               B           C
0   0.719391    0.091693    one
1   0.951499    0.83716     one
2   0.96454115  0.224855    one
3   0.80762     0.05846805  one
4   0.63319     0.342889    one
5   0.075102    0.87133205  one
6   0.502843    0.773424    one
7   0.05155265  0.242476    one
8   0.794938    0.607745    one
9   0.620387    0.574222    one
10  0.446639    0.549749    two
11  0.664324    0.134041    two
12  0.622217    0.505057    two
13  0.670338    0.96955755  two
14  0.281431    0.02949345  two
15  0.675756    0.185967    two
16  0.15391975  0.045686    two
17  0.404413    0.191482    two
18  0.8261117   0.943509    two
19  0.164642    0.157013    two

请注意,A 列的第 2、7、16 和 18 行已被替换; B 列的第 3、5、13 和 14 行已被替换。

有谁知道如何有效地处理大型数据框?

谢谢

您可以使用 groupby + quantile + clip:

g = df.groupby('C').transform(lambda x: x.clip(*x.quantile([0.05, 0.95])))
g['C'] = df['C']

           A         B    C
0   0.719391  0.091693  one
1   0.951499  0.837160  one
2   0.964541  0.224855  one
3   0.807620  0.058468  one
4   0.633190  0.342889  one
5   0.075102  0.871332  one
6   0.502843  0.773424  one
7   0.051553  0.242476  one
8   0.794938  0.607745  one
9   0.620387  0.574222  one
10  0.446639  0.549749  two
11  0.664324  0.134041  two
12  0.622217  0.505057  two
13  0.670338  0.969558  two
14  0.281431  0.029493  two
15  0.675756  0.185967  two
16  0.153920  0.045686  two
17  0.404413  0.191482  two
18  0.826112  0.943509  two
19  0.164642  0.157013  two

完整性检查

np.allclose(e[['A', 'B']].values, g[['A', 'B']].values)
True

这里,e是你问题的输出。

df.groupby('C')['A','B'].transform(lambda x : np.clip(x,x.quantile(0.05),x.quantile(0.95)))
Out[1599]: 
           A         B
0   0.719391  0.091693
1   0.951499  0.837160
2   0.964541  0.224855
3   0.807620  0.058468
4   0.633190  0.342889
5   0.075102  0.871332
6   0.502843  0.773424
7   0.051553  0.242476
8   0.794938  0.607745
9   0.620387  0.574222
10  0.446639  0.549749
11  0.664324  0.134041
12  0.622217  0.505057
13  0.670338  0.969558
14  0.281431  0.029493
15  0.675756  0.185967
16  0.153920  0.045686
17  0.404413  0.191482
18  0.826112  0.943509
19  0.164642  0.157013

为了加快速度,您可以使用此方法,但如果您有很多列,这将涉及更多的代码行。对于我的包含 200 万行的数据集,这是一种非常快速的方法 (<1s)。和你一样,.groupby 非常慢!

A_05 = df['A'].quantile(0.05)
A_95 = df['A'].quantile(0.95)
df['A'].clip(A_05, A_95, inplace=True)