在 Pandas 中按组保留 X% 的最后一行

mlx*_*mlx 6 python group-by pandas

使用类似df.groupby('ID').tail(N).

就我而言,组有不同的大小,我希望每个组保持相同的百分比而不是相同的行数。

例如,如果我们想为以下每个组(基于 ID)保留最后 50% 的行:

df = pd.DataFrame({'ID' : ['A','A','B','B','B','B','B','B'], 
'value' : [1,2,10,11,12,13,14,15]})
Run Code Online (Sandbox Code Playgroud)

结果是:

 pd.DataFrame({'ID' : ['A','A','B','B','B','B','B','B'], 
    'value' : [2,13,14,15]})
Run Code Online (Sandbox Code Playgroud)

我们怎样才能做到这一点?

编辑:如果 x% 不是 int,我们四舍五入到最小的更接近的 int。

tdy*_*tdy 9

groupby- apply-tail

通过所需大小tail()GroupBy.apply()。这比iloc下面的方法更简单,因为它干净地处理了“最后 0 行”的情况。

ratio = 0.6
(df.groupby('ID')
   .apply(lambda x: x.tail(int(ratio * len(x))))
   .reset_index(drop=True))

#   ID  value
# 0  A      2
# 1  B     13
# 2  B     14
# 3  B     15
Run Code Online (Sandbox Code Playgroud)
ratio = 0.4
(df.groupby('ID')
   .apply(lambda x: x.tail(int(ratio * len(x))))
   .reset_index(drop=True))

#   ID  value
# 0  B     14
# 1  B     15
Run Code Online (Sandbox Code Playgroud)

groupby- apply-iloc

或者,通过iloc/slicing索引所需的大小,但这更笨拙,因为[-0:]实际上并没有获得最后 0 行,因此我们必须检查:

ratio = 0.6
(df.groupby('ID')
   .apply(lambda x: x[-int(ratio * len(x)):] if int(ratio * len(x)) else None)
   .reset_index(drop=True))

#   ID  value
# 0  A      2
# 1  B     13
# 2  B     14
# 3  B     15
Run Code Online (Sandbox Code Playgroud)
ratio = 0.4
(df.groupby('ID')
   .apply(lambda x: x[-int(ratio * len(x)):] if int(ratio * len(x)) else None)
   .reset_index(drop=True))

#   ID  value
# 0  B     14
# 1  B     15
Run Code Online (Sandbox Code Playgroud)


Qua*_*ang 8

就像评论一样,没有内置选项可以这样做。您可以执行以下操作:

groups = df.groupby('ID')

enums = groups.cumcount().add(1)
sizes = groups['ID'].transform('size')

df[enums/sizes > 0.5]
Run Code Online (Sandbox Code Playgroud)

输出:

  ID  value
1  A      2
5  B     13
6  B     14
7  B     15
Run Code Online (Sandbox Code Playgroud)


WeN*_*Ben 5

让我们尝试两个步骤

s = df.groupby('ID').size()
out = df.groupby('ID').apply(lambda x : x.tail(s.loc[x.name]//2)).reset_index(drop=True)
out
Out[210]: 
  ID  value
0  A      2
1  B     13
2  B     14
3  B     15
Run Code Online (Sandbox Code Playgroud)