다음과 같은 df가 있습니다.
frame = pd.DataFrame({'a' : ['a,b,c', 'a,c,f', 'b,d,f','a,z,c']})
그리고 아이템 목록 :
letters = ['a','c']
내 목표는 frame
적어도 두 요소를 포함하는 모든 행을 얻는 것 입니다.letters
이 솔루션을 생각해 냈습니다.
for i in letters:
subframe = frame[frame['a'].str.contains(i)]
이것은 내가 원하는 것을 제공하지만 확장 성 측면에서 가장 좋은 해결책은 아닙니다. ‘벡터화 된’솔루션이 있습니까? 감사
답변
Series 목록을 작성한 다음 벡터화를 적용합니다 np.all
.
contains = [frame['a'].str.contains(i) for i in letters]
resul = frame[np.all(contains, axis=0)]
예상대로 제공됩니다.
a
0 a,b,c
1 a,c,f
3 a,z,c
답변
한 가지 방법은을 사용하여 열 값을 목록으로 나누고 얻은 목록 중 하나 str.split
인지 확인하는 것 set(letters)
입니다 subset
.
letters_s = set(letters)
frame[frame.a.str.split(',').map(letters_s.issubset)]
a
0 a,b,c
1 a,c,f
3 a,z,c
기준:
def serge(frame):
contains = [frame['a'].str.contains(i) for i in letters]
return frame[np.all(contains, axis=0)]
def yatu(frame):
letters_s = set(letters)
return frame[frame.a.str.split(',').map(letters_s.issubset)]
def austin(frame):
mask = frame.a.apply(lambda x: np.intersect1d(x.split(','), letters).size > 0)
return frame[mask]
def datanovice(frame):
s = frame['a'].str.split(',').explode().isin(letters).groupby(level=0).cumsum()
return frame.loc[s[s.ge(2)].index.unique()]
perfplot.show(
setup=lambda n: pd.concat([frame]*n, axis=0).reset_index(drop=True),
kernels=[
lambda df: serge(df),
lambda df: yatu(df),
lambda df: df[df['a'].apply(lambda x: np.all([*map(lambda l: l in x, letters)]))],
lambda df: austin(df),
lambda df: datanovice(df),
],
labels=['serge', 'yatu', 'bruno','austin', 'datanovice'],
n_range=[2**k for k in range(0, 18)],
equality_check=lambda x, y: x.equals(y),
xlabel='N'
)
답변
당신은 사용할 수 있습니다 np.intersect1d
:
import pandas as pd
import numpy as np
frame = pd.DataFrame({'a' : ['a,b,c', 'a,c,f', 'b,d,f','a,z,c']})
letters = ['a','c']
mask = frame.a.apply(lambda x: np.intersect1d(x.split(','), letters).size > 0)
print(frame[mask])
a
0 a,b,c
1 a,c,f
3 a,z,c
답변
이것은 또한 그것을 해결합니다 :
frame[frame['a'].apply(lambda x: np.all([*map(lambda l: l in x, letters)]))]
답변
set.issubset 사용하십시오 .
frame = pd.DataFrame({'a' : ['a,b,c', 'a,c,f', 'b,d,f','a,z,c','x,y']})
letters = ['a','c']
frame[frame['a'].apply(lambda x: set(letters).issubset(x))]
Out:
a
0 a,b,c
1 a,c,f
3 a,z,c
답변
IIUC explode
및 부울 필터
아이디어는 단일 시리즈를 만드는 것입니다. 그러면 누적 합계를 사용하여 목록의 실제 발생 횟수를 색인별로 그룹화 할 수 있습니다
s = frame['a'].str.split(',').explode().isin(letters).groupby(level=0).cumsum()
print(s)
0 1.0
0 1.0
0 2.0
1 1.0
1 2.0
1 2.0
2 0.0
2 0.0
2 0.0
3 1.0
3 1.0
3 2.0
frame.loc[s[s.ge(2)].index.unique()]
out:
a
0 a,b,c
1 a,c,f
3 a,z,c
답변
frame.iloc[[x for x in range(len(frame)) if set(letters).issubset(frame.iloc[x,0])]]
산출:
a
0 a,b,c
1 a,c,f
3 a,z,c
timeit
%%timeit
#hermes
frame.iloc[[x for x in range(len(frame)) if set(letters).issubset(frame.iloc[x,0])]]
산출
300 µs ± 32.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)