我想将pandas DataFrame过滤到特定行组中具有特定列值的最小数量的行。
例如,仅返回df的行/组,其中['c2','c3']组具有至少2行,且'c1'值为1:
df = pd.DataFrame({'c1':[0,1,0,1,1,0], 'c2':[0,0,0,1,1,1], 'c3':[0,0,0,1,1,1]})
结果应仅返回索引为3、4、5的行,因为只有[c2,c3] = [1,1]组具有至少2行,且'c1'值为1。
df.groupby(['c2','c3']).filter(lambda x: x['c1'].count() >= 2)
不返回所需的结果。我需要将该计数专门应用于1的计数,而不仅仅是'c1'的任何值。
以下方法有效,但我不确定如何使其更具Pythonic:
s = df.groupby(['c2','c3']).apply(lambda x: x[x['c1']==1].count() >= 2).all(axis=1)
df = df.reset_index().set_index(['c2','c3']).loc[s[s].index].reset_index().set_index(['index'])
答案 0 :(得分:3)
使用groupby
+ transform
对布尔系列求和,我们用它来掩盖原始DataFrame。
m = df['c1'].eq(1).groupby([df['c2'], df['c3']]).transform('sum').ge(2)
# Alterntively assign the column
#m = df.assign(to_sum = df.c1.eq(1)).groupby(['c2', 'c3']).to_sum.transform('sum').ge(2)
df.loc[m]
# c1 c2 c3
#3 1 1 1
#4 1 1 1
#5 0 1 1
使用过滤器,count
不是正确的逻辑。使用==
(或.eq()
)检查'c1'
等于特定值的位置。对布尔系列求和,并检查您的过滤器每组至少有2个这样的出现。
df.groupby(['c2','c3']).filter(lambda x: x['c1'].eq(1).sum() >= 2)
# c1 c2 c3
#3 1 1 1
#4 1 1 1
#5 0 1 1
虽然对于小型DataFrame来说并不明显,但随着组数的增加,带有filter
的{{1}}的速度非常慢。 lambda
很快:
transform
答案 1 :(得分:1)
可以使用groupby
+ merge
s=df.groupby(['c2','c3']).c1.sum().ge(2)
s[s].index.to_frame().reset_index(drop=True).merge(df,how='left')
c2 c3 c1
0 1 1 1
1 1 1 1
2 1 1 0