Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/300.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 使用具有特定值计数的GroupBy筛选数据帧_Python_Pandas_Pandas Groupby - Fatal编程技术网

Python 使用具有特定值计数的GroupBy筛选数据帧

Python 使用具有特定值计数的GroupBy筛选数据帧,python,pandas,pandas-groupby,Python,Pandas,Pandas Groupby,我想将一个数据帧过滤到特定行的组具有特定列值的最小计数的行 例如,仅返回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'].

我想将一个数据帧过滤到特定行的组具有特定列值的最小计数的行

例如,仅返回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)
不返回所需的结果。我需要将计数专门应用于1s的计数,而不仅仅是“c1”的任何值

以下方法可行,但我不确定如何使其更具python风格:

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'])    

使用
groupby
+
transform
对布尔序列求和,我们使用它来屏蔽原始数据帧

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'
是否等于特定值。求布尔级数的和,并检查过滤器的每个组中是否至少有两个这样的实例

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

虽然对于小数据帧来说并不明显,但随着组数的增加,带有
lambda
filter
的速度非常慢<代码>变换很快:

import numpy as np
np.random.seed(123)
df = pd.DataFrame({'c1':np.random.randint(1,100,1000), 'c2':np.random.randint(1,100,1000), 
                   'c3':np.random.choice([1,0], 1000)})

%%timeit
m = df['c1'].eq(1).groupby([df.c3, df.c3]).transform('sum').ge(2)
df.loc[m]
#5.21 ms ± 15.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.groupby(['c2','c3']).filter(lambda x: x['c1'].eq(1).sum() >= 2)
#124 ms ± 714 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

可以使用
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

非常有趣的方法。我不知道,即使将“c1”中的值1更改为“a”,df['c1'].eq('a').sum()也会“计算”真实值的数量。非常感谢。是的,.eq()返回一个布尔序列,当您应用像
.sum
这样的操作时,它将True强制为1,将False强制为0。@user7101631在这种情况下,我将按DataFrame列对一个序列进行分组,因此语法有点不同,需要分别传递分组列。如果您需要在原始数据框中使用许多列,那么我将使用
.assign
,创建需要求和的列,然后传递需要分组的列的列表
m=df.assign(to_sum=df.c1.eq(1)).groupby(['c2','c3'])。to_sum.transform('sum')。ge(2)