如何仅对数据框中的特定行进行排名?

时间:2017-09-30 17:30:36

标签: python pandas dataframe

我有一个数据框,其中包含参与行为的人员百分比,以及一般人群的索引。我想按索引对这些行为进行排名...... 我想从此排名中排除非常低的发生率行为。

如果我只是限制整个数据框以排除这些行为,那么很容易做到,但这里有捕获 - 我仍然希望将它们包含在我的df中;我只是不想把它们列入排名。

我的数据框是这样开始的,以group为索引:

GROUP     BEHAVIOR  SUBBEHAVIOR  PERCENT  INDEX
GROUP1    behavior1 foo          0.521    123
GROUP1    behavior2 bar          0.013    213
GROUP1    behavior2 fuzz         1.034    103
GROUP1    behavior3 foobar       0.750    131
GROUP2    behavior1 foo          1.521    101
GROUP2    behavior2 bar          0.913    91
GROUP2    behavior2 fuzz         0.034    301
GROUP2    behavior3 foobar       0.950    87

但是,我不想要第二排0.013排名。我想改为:

GROUP     BEHAVIOR  SUBBEHAVIOR  PERCENT  INDEX  RANK
GROUP1    behavior1 foo          0.521    123    2
GROUP1    behavior2 bar          0.013    213    NaN
GROUP1    behavior2 fuzz         1.034    103    3
GROUP1    behavior3 foobar       0.750    131    1
GROUP2    behavior1 foo          1.521    101    1
GROUP2    behavior2 bar          0.913    91     2
GROUP2    behavior2 fuzz         0.034    301    NaN
GROUP2    behavior3 foobar       0.950    87     3

我通过这样做实现了上述目标:

filtered = df[fd.loc[:,'PERCENT']>0.05].copy()
filtered['RANK'] = filtered.groupby(level=0).rank(ascending=False)['INDEX']
final = df.merge(filtered, on=df.columns.tolist(), how='left')

(我有更多的专栏使子行为真正独特,因此为什么我已经通过了所有df的列。)

它有效,但感觉就像一种非常混乱的方法,我想知道是否有更好,更优雅的方式。有吗?

2 个答案:

答案 0 :(得分:3)

两种方法

使用df.where

由于在groupby see here in docs)中自动排除了NA组,而rank的默认NA处理只是保留原样,您可以使用df.where为您的过滤器,直接进行。

df['RANK'] = (df.where(df.PERCENT > .05)
                 .groupby('GROUP')
                 .rank(ascending=False)
                 .INDEX)

>>> df

         BEHAVIOR  INDEX  PERCENT SUBBEHAVIOR  RANK
GROUP                                              
GROUP1  behavior1    123    0.521         foo   2.0
GROUP1  behavior2    213    0.013         bar   NaN
GROUP1  behavior2    103    1.034        fuzz   3.0
GROUP1  behavior3    131    0.750      foobar   1.0
GROUP2  behavior1    101    1.521         foo   1.0
GROUP2  behavior2     91    0.913         bar   2.0
GROUP2  behavior2    301    0.034        fuzz   NaN
GROUP2  behavior3     87    0.950      foobar   3.0

直截了当的解决方案

或者,只需先重置DataFrame上的索引,这样就可以使用标识符来对齐索引。

df.reset_index(inplace=True)
df['RANK'] = (df.query('PERCENT > .05')  # or using a mask ofc
                .groupby('GROUP')
                .rank(ascending=False)
                .INDEX)

query当然可以用类似df[df.PERCENT > .05]的布尔索引替换。

那么

>>> df.set_index('GROUP')

         BEHAVIOR SUBBEHAVIOR  PERCENT  INDEX  RANK
GROUP                                              
GROUP1  behavior1         foo    0.521    123   2.0
GROUP1  behavior2         bar    0.013    213   NaN
GROUP1  behavior2        fuzz    1.034    103   3.0
GROUP1  behavior3      foobar    0.750    131   1.0
GROUP2  behavior1         foo    1.521    101   1.0
GROUP2  behavior2         bar    0.913     91   2.0
GROUP2  behavior2        fuzz    0.034    301   NaN
GROUP2  behavior3      foobar    0.950     87   3.0

答案 1 :(得分:0)

df.join(df.loc[df['PERCENT']>0.05].groupby('GROUP')['INDEX'].rank(ascending=False).rename('RANK'))

如果在运行计算之前创建空白列,也可以使用.map()+ .insert()或.update()。