使用GroupBy过滤具有一定值的Pandas DataFrame

时间:2019-07-01 23:18:37

标签: python pandas pandas-groupby

我想将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'])    

2 个答案:

答案 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