熊猫 groupby 和过滤器
Posted
技术标签:
【中文标题】熊猫 groupby 和过滤器【英文标题】:Pandas groupby and filter 【发布时间】:2017-05-22 06:04:45 【问题描述】:我有数据框:
df = pd.DataFrame('ID':[1,1,2,2,3,3],
'YEAR' : [2011,2012,2012,2013,2013,2014],
'V': [0,1,1,0,1,0],
'C':[00,11,22,33,44,55])
我想按 ID 分组,并在每个组中选择 V = 0 的行。
这似乎不起作用:
print(df.groupby(['ID']).filter(lambda x: x['V'] == 0))
出现错误:
TypeError:过滤器函数返回一个系列,但期望一个标量布尔
如何使用过滤器来实现目标?谢谢。
编辑: V 上的条件可能因每个组而异,例如,对于 ID 1,它可能是 V==0,对于 ID 2,它可能是 V==1,并且可以通过另一个 DF 获得此信息:
df = pd.DataFrame('ID':[1,2,3],
'V': [0,1,0])
那么如何在每个组内进行行过滤呢?
【问题讨论】:
【参考方案1】:我认为groupby
不是必需的,仅在需要V
为0
的所有行时才使用boolean indexing
:
print (df[df.V == 0])
C ID V YEAR
0 0 1 0 2011
3 33 2 0 2013
5 55 3 0 2014
但如果需要返回至少一个列V
的值等于0
的所有组,添加any
,因为filter 需要True
或False
用于过滤组中的所有行:
print(df.groupby(['ID']).filter(lambda x: (x['V'] == 0).any()))
C ID V YEAR
0 0 1 0 2011
1 11 1 1 2012
2 22 2 1 2012
3 33 2 0 2013
4 44 3 1 2013
5 55 3 0 2014
更好的测试是更改groupby
的列 - 带有2012
的行被过滤掉,因为没有V==0
:
print(df.groupby(['YEAR']).filter(lambda x: (x['V'] == 0).any()))
C ID V YEAR
0 0 1 0 2011
3 33 2 0 2013
4 44 3 1 2013
5 55 3 0 2014
如果性能很重要,请使用 GroupBy.transform
和 boolean indexing
:
print(df[(df['V'] == 0).groupby(df['YEAR']).transform('any')])
ID YEAR V C
0 1 2011 0 0
3 2 2013 0 33
4 3 2013 1 44
5 3 2014 0 55
详情:
print((df['V'] == 0).groupby(df['YEAR']).transform('any'))
0 True
1 False
2 False
3 True
4 True
5 True
Name: V, dtype: bool
【讨论】:
你能参考这个创建新问题吗?您是否认为组中至少有一个值是V
和另一个数据框 df = pd.DataFrame('ID':[1,2,3], 'V': [0,1,0])
的值?如果将其更改为 df = pd.DataFrame('ID':[1,2,3], 'V': [0,1,2])
它不会返回最后一组所以输出是 'V': [0, 1, 1, 0], 'ID': [1, 1, 2, 2], 'C': [0, 11, 22, 33], 'YEAR': [2011, 2012, 2012, 2013]
?
@jezrael 如果我有 2 个字符串要检查 print(df.groupby(['YEAR']).filter(lambda x: (x['V'] == "abc" or x['V'] == "xyz").any()))
我认为你需要|
instaed or
(比较数组)并添加parenthesses
- print(df.groupby(['YEAR']).filter(lambda x: ((x['V'] == 0) | (x['V'] == 1)).any()))
另一种解决方案print(df.groupby(['YEAR']).filter(lambda x: (x['V'] == 0).any() or (x['V'] == 1)).any())
(不确定输出是否相同),但这里将标量与or
进行比较
我试过dfnew = df.groupby('OrderID').filter(lambda x: ((x['ResponseType']=='MODIFY_ORDER_REJECT') | x['ResponseType']=='CANCEL_ORDER_REJECT')).any() )
基本上我的意图是删除所有包含 MODIFY_ORDER_REJECT 或 CANCEL_ORDER_REJECT 的 OrderID 在 csv 中的任何位置。也许可以聊一分钟。谢谢以上是关于熊猫 groupby 和过滤器的主要内容,如果未能解决你的问题,请参考以下文章