pandas分组后选择行

5
在数据框架中,
 item_#, status, field1, field2 
   123,    "A",    "val1", "val2"
   223,    "B",    "val3", "val4"
   123,    "B",    "val5", "val6"
   323,    "A",    "val7", "val8"

我需要的是具有状态 "A" 和状态 "B"item_# 列表。 类似于 df.groupby('item_#').filter(lambda x: all(x['status'].isin(['A', 'B']))),但实际上这样并不能正常工作。它会获取列表中任意一个值的所有项目。

欢迎提出任何建议!


这个例子中,你想要什么样的输出? - Alex
一个包含状态"A"和"B"的商品的新数据框架,这种情况下,只包含商品_# ['123']。 - user3739312
3个回答

5
您可以使用 filter + isin
df.groupby('item_#').filter(lambda x : pd.Series(['A','B']).isin(x['status']).all())
Out[473]: 
   item_# status field1 field2
0     123      A   val1   val2
2     123      B   val5   val6

更新方法

df[df.groupby('item_#').status.transform(lambda x : {'A','B'}.issubset(set(x)))]
   item_# status field1 field2
0       1      A   val1   val2
2       1      B   val5   val6

1
您可以使用set
df[df.groupby('item_#')['status']
     .transform(lambda x: set(x.values.tolist()) == {'A','B'})]

输出:

项目_# 状态 字段1 字段2

0     123      A   val1   val2
2     123      B   val5   val6

1
当您声明一个已知元素的集合时,不应使用set关键字。只需使用大括号即可。此外,您可以像这样使用filter而不是transformdf.groupby('item_#').filter(lambda x: set(x['status']) >= {'A', 'B'}) - Ted Petrou
@TedPetrou 感谢你的改进。我认为,总的来说,使用布尔索引进行转换比使用过滤器慢。 - Scott Boston
1
简化解决方案怎么样 - 将 set(x.values.tolist()) 简化为 set(x) - jezrael

0

你也可以使用unstack、dropna和stack:

df.groupby(['item_#','status']).first().unstack().dropna().stack()
Out[136]: 
                    field1   field2
item_# status                      
123        "A"      "val1"   "val2"
           "B"      "val5"   "val6"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接