Python 查找包含多行匹配条件的组
给定以下数据帧Python 查找包含多行匹配条件的组,python,pandas,Python,Pandas,给定以下数据帧 df=pd.DataFrame({'A':list('aaaaaa bbbbb cccc'), “B”:列表('EFGHIJEGHJKGHJKEI')) 我想找到A中的所有元素,其中B包含“G”、“H”和“I” 因此,结果应该是 | | A | B | |---:|:----|:----| | 2 | A | G | | 3 | A | H | | 4 | A | I | | 11 | C | G | | 12 | C |
df=pd.DataFrame({'A':list('aaaaaa bbbbb cccc'),
“B”:列表('EFGHIJEGHJKGHJKEI'))
我想找到A
中的所有元素,其中B
包含“G”、“H”和“I”
因此,结果应该是
| | A | B |
|---:|:----|:----|
| 2 | A | G |
| 3 | A | H |
| 4 | A | I |
| 11 | C | G |
| 12 | C | H |
| 16 | C | I |
目前,我已经找到了下面的解决方案,但这似乎过于草率,我觉得我遗漏了一些明显的东西
hit=list('GHI'))
out=df[df.groupby('A')。应用(lambda x:(x['B'].isin(hit))和(x['B'].isin(hit).sum()==len(hit))。值]
让我们做groupby
+filter
hit = list('GHI')
out = df.groupby('A').filter(lambda x : pd.Series(hit).isin(x['B']).all())
out = out[out.B.isin(hit)]
out
Out[308]:
A B
2 A G
3 A H
4 A I
11 C G
12 C H
16 C I
这种转换不是很明显,但我们可以通过检查每个组的大小来保持它的矢量化,与
命中相比:
d = df[df['B'].isin(hit)]
size = d.groupby('A').size()
grps = size[size.eq(len(hit))].index
d[d['A'].isin(grps)]
你有两个条件:
hit是组的子集:x['B'].isin(hit).sum()==len(hit)
B处的值包含在hit:x['B']中。isin(hit)
所以你可以这样表达这两个条件
hit = frozenset('GHI')
print(df[df.groupby('A')['B'].transform(hit.issubset) & df['B'].isin(hit)])
输出
A B
2 A G
3 A H
4 A I
11 C G
12 C H
16 C I
表达方式:
df.groupby('A')['B'].transform(hit.issubset)
与条件1等效。另一种方法:首先删除那些未命中的,然后过滤所有命中的
(df[df['B'].isin(hit)]
.drop_duplicates(['A','B'])
.loc[lambda x: x.groupby('A')['A'].transform('size')==len(hit)]
)
或与groupby()类似的想法。过滤器:
(df[df['B'].isin(hit)]
.groupby('A')
.filter(lambda x: x['B'].nunique()==len(hit))
)
输出:
A B
2 A G
3 A H
4 A I
11 C G
12 C H
16 C I
下面是另一种使用布尔索引进行此操作的方法,无需使用groupby
和unstack
-
df = pd.DataFrame({'A':list('AAAAAABBBBBCCCCCC'),
'B':list('EFGHIJEGHJKGHJKEI')})
filt = df['B'].isin(hit)
df['C']=1
df[filt & df['A'].isin(df[filt].set_index(['A','B']).unstack('B').dropna().index)]
因为B有G和H,但不是i!我选择这个答案是因为我没有想到使用集合
。这个解决方案对我来说更“易读”
A B
2 A G
3 A H
4 A I
11 C G
12 C H
16 C I
df = pd.DataFrame({'A':list('AAAAAABBBBBCCCCCC'),
'B':list('EFGHIJEGHJKGHJKEI')})
filt = df['B'].isin(hit)
df['C']=1
df[filt & df['A'].isin(df[filt].set_index(['A','B']).unstack('B').dropna().index)]
A B C
2 A G 1
3 A H 1
4 A I 1
11 C G 1
12 C H 1
16 C I 1