感谢您的帮助。我对熊猫还比较陌生,在搜索结果中没有观察到这种特定的查询。
我有一个熊猫数据框:
+-----+---------+----------+
| id | value | match_id |
+-----+---------+----------+
| A10 | grass | 1 |
| B45 | cow | 3 |
| B98 | bird | 6 |
| B17 | grass | 1 |
| A20 | tree | 2 |
| A87 | farmer | 5 |
| B11 | grass | 1 |
| A33 | chicken | 4 |
| B56 | tree | 2 |
| A23 | farmer | 5 |
| B65 | cow | 3 |
+-----+---------+----------+
我需要过滤此数据框以查找包含匹配的match_id
值的行,条件是id
列还必须包含两个字符串A
< strong> 和 B
。
这是预期的输出:
+-----+-------+----------+
| id | value | match_id |
+-----+-------+----------+
| A10 | grass | 1 |
| B17 | grass | 1 |
| A20 | tree | 2 |
| B11 | grass | 1 |
| B56 | tree | 2 |
+-----+-------+----------+
我如何用一行熊猫代码做到这一点?下面的可复制程序:
import pandas as pd
data_example = {'id': ['A10', 'B45', 'B98', 'B17', 'A20', 'A87', 'B11', 'A33', 'B56', 'A23', 'B65'],
'value': ['grass', 'cow', 'bird', 'grass', 'tree', 'farmer', 'grass', 'chicken', 'tree', 'farmer', 'cow'],
'match_id': [1, 3, 6, 1, 2, 5, 1, 4, 2, 5, 3]}
df_example = pd.DataFrame(data=data_example)
data_expected = {'id': ['A10', 'B17', 'A20', 'B11', 'B56'],
'value': ['grass', 'grass', 'tree', 'grass', 'tree'],
'match_id': [1, 1, 2, 1, 2]}
df_expected = pd.DataFrame(data=data_expected)
谢谢!
答案 0 :(得分:2)
单行似乎很困难,但是您可以str.extract
从id中获得两个字符串,然后groupby
match_id并使用any
来查看每个match_id是否至少有一行所需的字符串,然后将all
与轴1结合使用,将True
赋予match_id这两个字符串。然后,您可以使用刚刚创建的系列在map
match_id列之后仅选择True match_id。
s = df_example['id'].str.extract('(A)|(B)').notna()\
.groupby(df_example['match_id']).any().all(1)
df_expected = df_example.loc[df_example['match_id'].map(s), :]
print (df_expected)
id value match_id
0 A10 grass 1
3 B17 grass 1
4 A20 tree 2
6 B11 grass 1
8 B56 tree 2
答案 1 :(得分:1)
@ Ben.T解决方案的另一种说法:
#create a helper column that combines the letters per gropu
res = (df_example
#the id column starts with a letter
.assign(letter = lambda x: x.id.str[0])
.groupby('match_id')
.letter.transform(','.join)
)
df['grp'] = res
df
id value match_id grp
0 A10 grass 1 A,B,B
1 B45 cow 3 B,B
2 B98 bird 6 B
3 B17 grass 1 A,B,B
4 A20 tree 2 A,B
5 A87 farmer 5 A,A
6 B11 grass 1 A,B,B
7 A33 chicken 4 A
8 B56 tree 2 A,B
9 A23 farmer 5 A,A
10 B65 cow 3 B,B
#filter for grps that contain A and B, and keep only relevant columns
df.loc[df.grp.str.contains('A,B'), "id":"match_id"]
id value match_id
0 A10 grass 1
3 B17 grass 1
4 A20 tree 2
6 B11 grass 1
8 B56 tree 2
#or u could use a list comprehension that assures u of both A and B (not just A following B)
filtered = [True if ("A" in ent) and ("B" in ent) else False for ent in df.grp.array]
df.loc[filtered,"id":"match_id"]
id value match_id
0 A10 grass 1
3 B17 grass 1
4 A20 tree 2
6 B11 grass 1
8 B56 tree 2