Python Pandas-두 데이터 프레임의 차이점 찾기


104

두 개의 데이터 프레임 df1과 df2가 있는데, 여기서 df2는 df1의 하위 집합입니다. 두 데이터 프레임의 차이 인 새 데이터 프레임 (df3)을 어떻게 얻습니까?

즉, df2에없는 df1의 모든 행 / 열이있는 데이터 프레임?

여기에 이미지 설명 입력


3
이를 수행하는 가장 쉬운 방법은 데이터 프레임이 구조화되는 방식 (즉, 인덱스 사용 가능 여부 등)에 따라 다릅니다. 이것은 팬더 질문에 항상 재현 가능한 예 를 포함해야하는 이유에 대한 좋은 예입니다 .
cmaher

1
데이터 프레임 샘플 이미지를 추가했습니다
userPyGeo

답변:


163

사용하여 drop_duplicates

pd.concat([df1,df2]).drop_duplicates(keep=False)

Update :

Above method only working for those dataframes they do not have duplicate itself, For example

df1=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})
df2=pd.DataFrame({'A':[1],'B':[2]})

아래와 같이 출력됩니다.

잘못된 출력 :

pd.concat([df1, df2]).drop_duplicates(keep=False)
Out[655]: 
   A  B
1  2  3

올바른 출력

Out[656]: 
   A  B
1  2  3
2  3  4
3  3  4

그것을 달성하는 방법?

방법 1 : isin함께 사용tuple

df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]
Out[657]: 
   A  B
1  2  3
2  3  4
3  3  4

방법 2 : mergeindicator

df1.merge(df2,indicator = True, how='left').loc[lambda x : x['_merge']!='both']
Out[421]: 
   A  B     _merge
1  2  3  left_only
2  3  4  left_only
3  3  4  left_only

4
또한 중복을 찾을 때, 고려되어야하는 열을 결정할 수있다 :pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)
Szpaqn

1
@Szpaqn은이 메서드가 특수한 경우를 처리하지 않는다는 것을 알립니다. :-)
BENY

이로 인해 데이터 유형 중 하나가 float(때문에 12.00000000001 != 12) 인 경우 결과에 예기치 않은 행이 남아있을 수 있습니다 . 더 나은 방법은 두 데이터 프레임에서 설정된 ID의 교차점을 찾아 그에 따라 차이를 얻는 것입니다.
Jiāgěng

1
@DtechNet 두 데이터 프레임을 같은 이름으로
만들어야합니다

2
방법 2 ( indicator=True)는 매우 다재다능하고 유용한 도구 이므로이 답변의 상단에서보고 싶지만 '왼쪽'이 아닌 '외부'로 3 가지 상황을 모두 포함합니다.
mirekphd

34

행의 경우 다음을 시도하십시오 Name. 결합 인덱스 열은 어디 입니까? (여러 공통 열에 대한 목록이거나 left_on및 지정 가능 right_on) :

m = df1.merge(df2, on='Name', how='outer', suffixes=['', '_'], indicator=True)

indicator=True설정은 "left_only", "right_only"또는 "both"의 3 가지 종류로 분류 된 및 _merge사이의 모든 변경 사항이있는 이라는 열을 추가하므로 유용합니다 .df1df2

열의 경우 다음을 시도하십시오.

set(df1.columns).symmetric_difference(df2.columns)

9
댓글을 달고 싶으신가요? mergewith indicator=True는 주어진 필드로 데이터 프레임을 비교하는 고전적인 솔루션입니다.
jpp

9

허용 된 답변 방법 1은 NaN이 내부에있는 데이터 프레임에 대해 작동하지 않습니다 pd.np.nan != pd.np.nan. 이것이 최선의 방법인지 확실하지 않지만 다음 방법으로 피할 수 있습니다.

df1[~df1.astype(str).apply(tuple, 1).isin(df2.astype(str).apply(tuple, 1))]

7

edit2, 인덱스 설정없이 새로운 솔루션을 찾았습니다.

newdf=pd.concat([df1,df2]).drop_duplicates(keep=False)

좋아, 나는 가장 높은 투표의 대답에 이미 내가 알아 낸 것을 포함하고 있음을 발견했다. 예, 두 개의 df에 중복이없는 경우에만이 코드를 사용할 수 있습니다.


까다로운 방법이 있습니다. 먼저 질문에서 주어진 두 데이터 프레임의 인덱스로 '이름'을 설정합니다. 두 개의 df에 동일한 'Name'이 있으므로 'bigger'df에서 'smaller'df의 인덱스를 삭제할 수 있습니다. 다음은 코드입니다.

df1.set_index('Name',inplace=True)
df2.set_index('Name',inplace=True)
newdf=df1.drop(df2.index)

1
당신은 아마도 pd.concat ([df1, df2]). drop_duplicates (keep = False)를 의미했을 것입니다
Manaslu

4
import pandas as pd
# given
df1 = pd.DataFrame({'Name':['John','Mike','Smith','Wale','Marry','Tom','Menda','Bolt','Yuswa',],
    'Age':[23,45,12,34,27,44,28,39,40]})
df2 = pd.DataFrame({'Name':['John','Smith','Wale','Tom','Menda','Yuswa',],
    'Age':[23,12,34,44,28,40]})

# find elements in df1 that are not in df2
df_1notin2 = df1[~(df1['Name'].isin(df2['Name']) & df1['Age'].isin(df2['Age']))].reset_index(drop=True)

# output:
print('df1\n', df1)
print('df2\n', df2)
print('df_1notin2\n', df_1notin2)

# df1
#     Age   Name
# 0   23   John
# 1   45   Mike
# 2   12  Smith
# 3   34   Wale
# 4   27  Marry
# 5   44    Tom
# 6   28  Menda
# 7   39   Bolt
# 8   40  Yuswa
# df2
#     Age   Name
# 0   23   John
# 1   12  Smith
# 2   34   Wale
# 3   44    Tom
# 4   28  Menda
# 5   40  Yuswa
# df_1notin2
#     Age   Name
# 0   45   Mike
# 1   27  Marry
# 2   39   Bolt

'~'는 무슨 뜻인가요?
Piotrek Leśniak

'~'는 부울 인덱싱 용이 아닙니다. 참조 : pandas.pydata.org/pandas-docs/stable/user_guide/…
SpeedCoder5

3

아마도 동일하거나 다른 열 이름을 가진 더 간단한 한 줄짜리 일 것입니다. df2 [ 'Name2']에 중복 값이 ​​포함 된 경우에도 작동했습니다.

newDf = df1.set_index('Name1')
           .drop(df2['Name2'], errors='ignore')
           .reset_index(drop=False)

2
간단하고 효과적입니다. 대상 값이 소스에없는 경우 (예 : 교차점) 문제를 해결하기 위해 errors = 'ignore'가 추가되고 마지막에 인덱스를 재설정하면 원본과 유사한 df가 생성됩니다.
MrE

1

여기 에서 언급했듯이

df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]

올바른 솔루션이지만 다음과 같은 경우 잘못된 출력을 생성합니다.

df1=pd.DataFrame({'A':[1],'B':[2]})
df2=pd.DataFrame({'A':[1,2,3,3],'B':[2,3,4,4]})

이 경우 위의 솔루션은 Empty DataFrame 을 제공 하지만 대신 사용해야합니다.concat 각 datframe에서 중복을 제거한 후 메서드 .

사용하다 concate with drop_duplicates

df1=df1.drop_duplicates(keep="first") 
df2=df2.drop_duplicates(keep="first") 
pd.concat([df1,df2]).drop_duplicates(keep=False)

질문의 작성자는 df2에없는 df1의 모든 값을 반환하도록 요청했습니다. 따라서이 df1[~df1.apply(tuple,1).isin(df2.apply(tuple,1))]경우에도 정답입니다. df1 또는 df2에 있지만 둘 다가 아닌 값을 얻으려는 경우 제안 된 접근 방식이 정확합니다 (원래 데이터 프레임에서 중복 제거에 대한주의 사항 포함).
ira

0

기존 데이터 프레임의 인덱스를 변경할 필요가없는 멋진 @liangli 솔루션의 약간 변형 :

newdf = df1.drop(df1.join(df2.set_index('Name').index))

0

인덱스로 차이 찾기. df1이 df2의 하위 집합이고 하위 집합시 인덱스가 이월된다고 가정합니다.

df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()

# Example

df1 = pd.DataFrame({"gender":np.random.choice(['m','f'],size=5), "subject":np.random.choice(["bio","phy","chem"],size=5)}, index = [1,2,3,4,5])

df2 =  df1.loc[[1,3,5]]

df1

 gender subject
1      f     bio
2      m    chem
3      f     phy
4      m     bio
5      f     bio

df2

  gender subject
1      f     bio
3      f     phy
5      f     bio

df3 = df1.loc[set(df1.index).symmetric_difference(set(df2.index))].dropna()

df3

  gender subject
2      m    chem
4      m     bio


0

받아 들여진 답변 외에도 / ( 두 데이터 프레임에 대해 일치하지 않을 수 있음)를 사용하여 두 데이터 프레임 의 2D 세트 차이 를 찾을 수있는 더 넓은 솔루션을 제안하고 싶습니다 . 또한 방법은 데이터 프레임 비교를 위해 요소에 대한 허용 오차를 설정할 수 있습니다 (사용 )indexcolumnsfloatnp.isclose


import numpy as np
import pandas as pd

def get_dataframe_setdiff2d(df_new: pd.DataFrame, 
                            df_old: pd.DataFrame, 
                            rtol=1e-03, atol=1e-05) -> pd.DataFrame:
    """Returns set difference of two pandas DataFrames"""

    union_index = np.union1d(df_new.index, df_old.index)
    union_columns = np.union1d(df_new.columns, df_old.columns)

    new = df_new.reindex(index=union_index, columns=union_columns)
    old = df_old.reindex(index=union_index, columns=union_columns)

    mask_diff = ~np.isclose(new, old, rtol, atol)

    df_bool = pd.DataFrame(mask_diff, union_index, union_columns)

    df_diff = pd.concat([new[df_bool].stack(),
                         old[df_bool].stack()], axis=1)

    df_diff.columns = ["New", "Old"]

    return df_diff

예:

In [1]

df1 = pd.DataFrame({'A':[2,1,2],'C':[2,1,2]})
df2 = pd.DataFrame({'A':[1,1],'B':[1,1]})

print("df1:\n", df1, "\n")

print("df2:\n", df2, "\n")

diff = get_dataframe_setdiff2d(df1, df2)

print("diff:\n", diff, "\n")
Out [1]

df1:
   A  C
0  2  2
1  1  1
2  2  2 

df2:
   A  B
0  1  1
1  1  1 

diff:
     New  Old
0 A  2.0  1.0
  B  NaN  1.0
  C  2.0  NaN
1 B  NaN  1.0
  C  1.0  NaN
2 A  2.0  NaN
  C  2.0  NaN 
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.