使用 pandas groupby 和过滤器删除行
drop rows using pandas groupby and filter
我正在尝试从满足特定条件的 df 中删除行。在下面,我使用 C
列对值进行分组。对于每个唯一组,我想删除 A
小于 1
且 B
大于 100
的所有行。不过,这必须发生在同一行。如果我使用 .any()
或 .all()
,它不会 return 我想要的。
df = pd.DataFrame({
'A' : [1,0,1,0,1,0,0,1,0,1],
'B' : [101, 2, 3, 1, 5, 101, 2, 3, 4, 5],
'C' : ['d', 'd', 'd', 'd', 'e', 'e', 'e', 'f', 'f',],
})
df.groupby(['C']).filter(lambda g: g['A'].lt(1) & g['B'].gt(100))
初始 df:
A B C
0 1 101 d # A is not lt 1 so keep all d's
1 0 2 d
2 1 3 d
3 0 1 d
4 1 5 e
5 0 101 e # A is lt 1 and B is gt 100 so drop all e's
6 0 2 e
7 1 3 f
8 0 4 f
9 1 5 f
意在:
A B C
0 1 101 d
1 0 2 d
2 1 3 d
3 0 1 d
7 1 3 f
8 0 4 f
9 1 5 f
为了获得更好的性能,获取所有 C
值匹配条件,然后通过 Series.isin
in boolean indexing
使用反向掩码过滤原始列 C
:
df1 = df[~df['C'].isin(df.loc[df['A'].lt(1) & df['B'].gt(100), 'C'])]
另一种想法是使用 GroupBy.transform
with GroupBy.any
来测试是否匹配至少一个值:
df1 = df[~(df['A'].lt(1) & df['B'].gt(100)).groupby(df['C']).transform('any')]
您的解决方案可以使用 any
和 not
作为标量,如果 DataFrame 很大,它应该很慢:
df1 = df.groupby(['C']).filter(lambda g:not ( g['A'].lt(1) & g['B'].gt(100)).any())
df1 = df.groupby(['C']).filter(lambda g: (g['A'].ge(1) | g['B'].le(100)).all())
print (df1)
A B C
0 1 101 d
1 0 2 d
2 1 3 d
3 0 1 d
7 1 3 f
8 0 4 f
9 1 5 f
我正在尝试从满足特定条件的 df 中删除行。在下面,我使用 C
列对值进行分组。对于每个唯一组,我想删除 A
小于 1
且 B
大于 100
的所有行。不过,这必须发生在同一行。如果我使用 .any()
或 .all()
,它不会 return 我想要的。
df = pd.DataFrame({
'A' : [1,0,1,0,1,0,0,1,0,1],
'B' : [101, 2, 3, 1, 5, 101, 2, 3, 4, 5],
'C' : ['d', 'd', 'd', 'd', 'e', 'e', 'e', 'f', 'f',],
})
df.groupby(['C']).filter(lambda g: g['A'].lt(1) & g['B'].gt(100))
初始 df:
A B C
0 1 101 d # A is not lt 1 so keep all d's
1 0 2 d
2 1 3 d
3 0 1 d
4 1 5 e
5 0 101 e # A is lt 1 and B is gt 100 so drop all e's
6 0 2 e
7 1 3 f
8 0 4 f
9 1 5 f
意在:
A B C
0 1 101 d
1 0 2 d
2 1 3 d
3 0 1 d
7 1 3 f
8 0 4 f
9 1 5 f
为了获得更好的性能,获取所有 C
值匹配条件,然后通过 Series.isin
in boolean indexing
使用反向掩码过滤原始列 C
:
df1 = df[~df['C'].isin(df.loc[df['A'].lt(1) & df['B'].gt(100), 'C'])]
另一种想法是使用 GroupBy.transform
with GroupBy.any
来测试是否匹配至少一个值:
df1 = df[~(df['A'].lt(1) & df['B'].gt(100)).groupby(df['C']).transform('any')]
您的解决方案可以使用 any
和 not
作为标量,如果 DataFrame 很大,它应该很慢:
df1 = df.groupby(['C']).filter(lambda g:not ( g['A'].lt(1) & g['B'].gt(100)).any())
df1 = df.groupby(['C']).filter(lambda g: (g['A'].ge(1) | g['B'].le(100)).all())
print (df1)
A B C
0 1 101 d
1 0 2 d
2 1 3 d
3 0 1 d
7 1 3 f
8 0 4 f
9 1 5 f