programing

panda - 데이터 프레임을 다른 데이터 프레임 단위로 행 요소 단위로 필터링합니다.

powerit 2023. 10. 25. 23:51
반응형

panda - 데이터 프레임을 다른 데이터 프레임 단위로 행 요소 단위로 필터링합니다.

데이터 프레임이 있습니다.df1다음과 같이 보입니다.

   c  k  l
0  A  1  a
1  A  2  b
2  B  2  a
3  C  2  a
4  C  2  d

그리고 또 하나의 부름을 받았습니다.df2예:

   c  l
0  A  b
1  C  a

필터링하고 싶습니다.df1포함되지 않은 값만df2. 필터링할 값은 다음과 같습니다.(A,b)그리고.(C,a)튜플지금까지 제가 적용을 해봤습니다.isin방법:

d = df[~(df['l'].isin(dfc['l']) & df['c'].isin(dfc['c']))]

제가 보기엔 너무 복잡하네요, 다시 돌아오네요.

   c  k  l
2  B  2  a
4  C  2  d

하지만 기대하고 있습니다.

   c  k  l
0  A  1  a
2  B  2  a
4  C  2  d

를 사용하여 효율적으로 작업할 수 있습니다.isin원하는 열로 구성된 다중 인덱스 상에서:

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})
keys = list(df2.columns.values)
i1 = df1.set_index(keys).index
i2 = df2.set_index(keys).index
df1[~i1.isin(i2)]

enter image description here

@IanS의 유사한 솔루션은 열 유형을 가정하지 않기 때문에 개선되었다고 생각합니다(즉, 문자열뿐만 아니라 숫자로도 작동함).


(위의 답변은 편집입니다.다음은 저의 첫 번째 답변이었습니다.)

재미있네요!전에 본 적이 없는 일인데요저는 아마 두 배열을 병합한 다음에 다음과 같은 행을 놓음으로써 해결할 것입니다.df2정의되어 있습니다.임시 배열을 사용하는 예는 다음과 같습니다.

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})

# create a column marking df2 values
df2['marker'] = 1

# join the two, keeping all of df1's indices
joined = pd.merge(df1, df2, on=['c', 'l'], how='left')
joined

enter image description here

# extract desired columns where marker is NaN
joined[pd.isnull(joined['marker'])][df1.columns]

enter image description here

임시 배열을 사용하지 않고 이것을 할 수 있는 방법이 있을지 모르지만, 저는 그 방법이 생각나지 않습니다.데이터가 방대하지 않은 한 위의 방법이 빠르고 충분한 답이 될 것입니다.

이는 매우 간단하며 잘 작동합니다.

df1 = df1[~df1.index.isin(df2.index)]

사용하기 & :

더 우아한 방법은 하는 것일 것입니다.left join의론으로indicator=True, 그런 다음 모든 행을 필터링합니다.left_only와 함께query:

d = (
    df1.merge(df2, 
              on=['c', 'l'],
              how='left', 
              indicator=True)
    .query('_merge == "left_only"')
    .drop(columns='_merge')
)

print(d)
   c  k  l
0  A  1  a
2  B  2  a
4  C  2  d

indicator=True추가 열이 있는 데이터 프레임을 반환합니다._merge각 행을 표시하는 것.left_only, both, right_only:

df1.merge(df2, on=['c', 'l'], how='left', indicator=True)

   c  k  l     _merge
0  A  1  a  left_only
1  A  2  b       both
2  B  2  a  left_only
3  C  2  a       both
4  C  2  d  left_only

다른 데이터 프레임의 여러 열을 기준으로 데이터 프레임을 필터링하거나 사용자 지정 목록을 기준으로 필터링하려는 경우에는 이 방법이 매우 간단하다고 생각합니다.

df1 = pd.DataFrame({'c': ['A', 'A', 'B', 'C', 'C'],
                    'k': [1, 2, 2, 2, 2],
                    'l': ['a', 'b', 'a', 'a', 'd']})
df2 = pd.DataFrame({'c': ['A', 'C'],
                    'l': ['b', 'a']})

#values of df2 columns 'c' and 'l' that will be used to filter df1
idxs = list(zip(df2.c.values, df2.l.values)) #[('A', 'b'), ('C', 'a')]

#so df1 is filtered based on the values present in columns c and l of df2 (idxs)
df1 = df1[pd.Series(list(zip(df1.c, df1.l)), index=df1.index).isin(idxs)]

다음은 어떻습니까?

df1['key'] = df1['c'] + df1['l']
d = df1[~df1['key'].isin(df2['c'] + df2['l'])].drop(['key'], axis=1)

추가 열을 만들거나 병합하는 것을 피하는 또 다른 방법은 df2에 그룹을 만들어 별개의 (c, l) 쌍을 얻은 다음 이를 사용하여 df1을 필터링하는 것입니다.

gb = df2.groupby(("c", "l")).groups
df1[[p not in gb for p in zip(df1['c'], df1['l'])]]]

이 작은 예를 들어, 실제로 팬더 기반 접근 방식(666 µ 대 1.76ms)보다 조금 더 빨리 실행되는 것처럼 보이지만, 순수 파이썬으로 떨어지고 있기 때문에 더 큰 예에서는 더 느릴 수 있다고 생각합니다.

두 DataFrame을 연결하고 모든 중복을 삭제할 수 있습니다.

df1.append(df2).drop_duplicates(subset=['c', 'l'], keep=False)

출력:

   c    k  l
0  A  1.0  a
2  B  2.0  a
4  C  2.0  d

중복되는 경우에는 이 방법을 사용할 수 없습니다.subset=['c', 'l']인에df1.

언급URL : https://stackoverflow.com/questions/33282119/pandas-filter-dataframe-by-another-dataframe-by-row-elements

반응형