将值设置为DataFrame中每列的第90个百分位数

时间:2015-04-27 10:05:00

标签: python pandas dataframe vectorization percentile

我正在处理看起来像

所描述的DataFrame的数据
df = pd.DataFrame({'AAA': [1,1,1,2,2,2,3,3], 'BBB': [2,1,3,4,6,1,2,3]})

如果价值超过第90个百分点,我想做的是将值设置为综合(90%)。所以它就像把最大值限制在第90个百分位。

这对我来说变得越来越棘手,因为每列都会有不同的百分位值。

我可以使用以下方法获得第90个百分位值:

df.describe(percentiles=[.9])

因此对于BBB列,6大于4.60(第90百分位数),因此需要将其更改为5(综合4.60)。

在我的实际问题中,我正在为一个大矩阵做这个,所以我想知道是否有任何简单的解决方案,而不是首先创建一个90%的列数组,然后检查列中的元素并将这些数据设置为90%。

2 个答案:

答案 0 :(得分:2)

一种矢量化方法是合并np.minimumdf.quantile

>>> np.minimum(df, df.quantile(0.9))
   AAA  BBB
0    1  2.0
1    1  1.0
2    1  3.0
3    2  4.0
4    2  4.6
5    2  1.0
6    3  2.0
7    3  3.0

为了更大的速度提升使用:

np.minimum(df, np.percentile(df, 90, axis=0))

df.quantile似乎比np.percentile慢(可能是因为它返回的是Series而不是普通的NumPy数组)。

答案 1 :(得分:1)

执行此操作的一种方法是对每列使用clip_upper() 90%百分位值np.percentile(x, 90)

In [242]: df.apply(lambda x: x.clip_upper(np.percentile(x, 90)))
Out[242]:
   AAA  BBB
0    1  2.0
1    1  1.0
2    1  3.0
3    2  4.0
4    2  4.6
5    2  1.0
6    3  2.0
7    3  3.0

我想象@ajcr优雅的解决方案会比apply更快。的但是,

低于len(df) ~ 130K

的基准
In [245]: %timeit df.apply(lambda x: x.clip_upper(np.percentile(x, 90)))
100 loops, best of 3: 7.49 ms per loop

In [246]: %timeit np.minimum(df, df.quantile(0.9))
100 loops, best of 3: 11.1 ms per loop

适用于len(df) ~ 1M

In [248]: %timeit df.apply(lambda x: x.clip_upper(np.percentile(x, 90)))
10 loops, best of 3: 54.5 ms per loop

In [249]: %timeit np.minimum(df, df.quantile(0.9))
10 loops, best of 3: 73.9 ms per loop