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。
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)
就像评论一样,没有内置选项可以这样做。您可以执行以下操作:
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)
让我们尝试两个步骤
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)