programing

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

goodcopy 2023. 1. 30. 22:31
반응형

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

2개의 데이터 프레임 df1과 df2가 있습니다.df2는 df1의 서브셋입니다.두 데이터 프레임 간의 차이인 새 데이터 프레임(df3)을 얻으려면 어떻게 해야 합니까?

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

여기에 이미지 설명 입력

사용방법drop_duplicates

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

Update :

The above method only works for those data frames that don't already have duplicates themselves. 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:.merge와 함께indicator

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

행의 경우는, 이것을 사용해 주세요.Name는 조인트 인덱스 컬럼입니다(여러 공통 컬럼의 리스트가 될 수 있습니다).또는, 지정해 주세요.left_on그리고.right_on):

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

indicator=True설정은 다음과 같은 컬럼을 추가하기 때문에 편리합니다._merge(모든 변경 사항 포함)df1그리고.df2"left_only", "right_only" 또는 "both"의 3가지 종류로 분류됩니다.

열의 경우 다음과 같이 하십시오.

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

승인된 응답 방법1은 NaN이 내부에 있는 데이터 프레임에서는 다음과 같이 동작하지 않습니다.pd.np.nan != pd.np.nan이 방법이 최선인지는 잘 모르겠지만, 이 방법으로는 피할 수 있습니다.

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

데이터를 문자열에 캐스트해야 하기 때문에 속도가 느리지만, 이 캐스트 덕분에pd.np.nan == pd.np.nan.

암호를 살펴봅시다.우선 문자열에 값을 캐스팅하고,tuple각 행에 대해 기능합니다.

df1.astype(str).apply(tuple, 1)
df2.astype(str).apply(tuple, 1)

그 덕분에 우리는pd.Series튜플 리스트가 있는 객체.각 태플에는 다음 행이 포함됩니다.df1/df2그럼 신청하겠습니다.isin에 대한 방법.df1각 태플이 들어가 있는지 확인하다df2그 결과는pd.SeriesBool 가치관을 가지고 있습니다.turple이 true인 경우 true입니다.df1df2최종적으로는, 다음과 같이 결과를 부정합니다.~서명 및 필터 적용df1간단히 말해서, 우리는 그 줄들만 가지고 있다.df1에 없는 것df2.

보다 읽기 쉽게 하기 위해 다음과 같이 쓸 수 있습니다.

df1_str_tuples = df1.astype(str).apply(tuple, 1)
df2_str_tuples = df2.astype(str).apply(tuple, 1)
df1_values_in_df2_filter = df1_str_tuples.isin(df2_str_tuples)
df1_values_not_in_df2 = df1[~df1_values_in_df2_filter]
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

열 이름이 같거나 다른 단순한 한 줄일 수 있습니다.df2['Name2']에 중복된 값이 포함되어 있는 경우에도 동작합니다.

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

edit2, 인덱스를 설정할 필요 없이 새로운 솔루션을 찾아냈다.

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

좋아, 최고 투표의 답은 이미 내가 알아낸 것을 포함하고 있다는 걸 찾았어.네, 이 코드는 2개의 DFS 각각에 중복이 없는 경우에만 사용할 수 있습니다.


저는 까다로운 방법을 가지고 있어요.먼저 문제에서 주어진 두 데이터 프레임의 인덱스로 '이름'을 설정했습니다.2개의 DFS에 같은 '이름'이 있기 때문에 '큰'df에서 '작은'df 인덱스를 삭제하기만 하면 됩니다.여기 암호가 있습니다.

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

수용된 답변 외에, 저는 두 데이터 프레임의 2D 세트 차이를 찾을 수 있는 더 넓은 솔루션을 제안하고 싶습니다.index/columns(두 데이터 이름이 일치하지 않을 수 있습니다)., 이 방법을 하면, 할 수 .float비교용 (「」를 합니다)np.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 

여기서 말한 바와 같이

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]})

이 경우 위의 솔루션은 빈 데이터 프레임을 제공합니다.대신,concat각 데이터 프레임에서 중복을 제거한 후 메서드를 지정합니다.

concate with drop_duplicates

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

이 있을 때 에 중복을 취급하는 데 가 있었습니다.Counter.collections양쪽의 카운트가 같은 것을 확인하고, 보다 나은 차이를 실현합니다.중복은 반환되지 않지만 양쪽의 카운트가 같으면 반환되지 않습니다.

from collections import Counter

def diff(df1, df2, on=None):
    """
    :param on: same as pandas.df.merge(on) (a list of columns)
    """
    on = on if on else df1.columns
    df1on = df1[on]
    df2on = df2[on]
    c1 = Counter(df1on.apply(tuple, 'columns'))
    c2 = Counter(df2on.apply(tuple, 'columns'))
    c1c2 = c1-c2
    c2c1 = c2-c1
    df1ondf2on = pd.DataFrame(list(c1c2.elements()), columns=on)
    df2ondf1on = pd.DataFrame(list(c2c1.elements()), columns=on)
    df1df2 = df1.merge(df1ondf2on).drop_duplicates(subset=on)
    df2df1 = df2.merge(df2ondf1on).drop_duplicates(subset=on)
    return pd.concat([df1df2, df2df1])
> df1 = pd.DataFrame({'a': [1, 1, 3, 4, 4]})
> df2 = pd.DataFrame({'a': [1, 2, 3, 4, 4]})
> diff(df1, df2)
   a
0  1
0  2

Panda는 이제 데이터 프레임 차이를 실현하기 위한 새로운 API를 제공합니다.pandas.DataFrame.compare

df.compare(df2)
  col1       col3
  self other self other
0    a     c  NaN   NaN
2  NaN   NaN  3.0   4.0

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

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

인덱스별 차이를 찾는 중입니다.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

데이터 프레임 정의:

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

df2 = df1[df1.Name.isin(['John','Smith','Wale','Tom','Menda','Yuswa'])

df1

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

df2

    Name  Age
0   John   23
2  Smith   12
3   Wale   34
5    Tom   44
6  Menda   28
8  Yuswa   40

두 가지 차이는 다음과 같습니다.

df1[~df1.isin(df2)].dropna()

    Name   Age
1   Mike  45.0
4  Marry  27.0
7   Bolt  39.0

장소:

  • df1.isin(df2) 있는 합니다.df1 있다df2.
  • ~ ( NOT에 Element-wise logical NOT(Element-wise logical NOT)의 요소를 수 df1 없는 것df2- ★★★★★★★★★★★★★★★★」
  • .dropna()과 행이 어긋나다NaN 표시

주의: 이것은, 다음의 경우에만 유효합니다.len(df1) >= len(df2).df2보다 df1하면 됩니다.df2[~df2.isin(df1)].dropna()

deepdiff라이브러리는 다른 세부 정보가 필요하거나 주문에 문제가 있는 경우 데이터 프레임으로도 확장 가능한 훌륭한 도구입니다.Diffing을 실험할 수 있습니다.to_dict('records'),to_numpy()및 기타 , " " " " 。

import pandas as pd
from deepdiff import DeepDiff

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

df2 = df1[df1.Name.isin(['John','Smith','Wale','Tom','Menda','Yuswa'])]

DeepDiff(df1.to_dict(), df2.to_dict())
# {'dictionary_item_removed': [root['Name'][1], root['Name'][4], root['Name'][7], root['Age'][1], root['Age'][4], root['Age'][7]]}

을 '하다'로 할 수 ._merge 가 value“left_only”df1되어 있다df2

df3 = df1.merge(df2, how = 'outer' ,indicator=True).loc[lambda x :x['_merge']=='left_only']
df

언급URL : https://stackoverflow.com/questions/48647534/python-pandas-find-difference-between-two-data-frames

반응형