programing

두 데이터 프레임 간의 차이 찾기

minimums 2023. 9. 5. 20:05
반응형

두 데이터 프레임 간의 차이 찾기

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

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

enter image description here

을 사용하여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: 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: 방법 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"의 세 가지 가능한 종류로 분류됩니다.

열의 경우 다음을 수행합니다.

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.Series가치가 있는.tuple의 입니다.df1안에 있습니다.df2, 우는결부정으로 결과를 합니다.~ 명서, 터적에 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

Pandas는 이제 데이터 프레임 차이를 수행할 수 있는 새로운 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

열 이름이 같거나 다른 단순한 단일 선일 수 있습니다.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)

네, 저는 최고 투표의 답이 이미 제가 알아낸 것을 포함하고 있다는 것을 발견했습니다.예, 이 코드는 각 두 개의 dfs에 중복이 없는 경우에만 사용할 수 있습니다.


저는 까다로운 방법이 있습니다.먼저 '이름'을 질문에 의해 주어진 두 데이터 프레임의 인덱스로 설정합니다.두 개의 dfs에 동일한 '이름'이 있으므로 '더 큰' dfs에서 '더 작은' dfs 인덱스를 삭제하면 됩니다.여기 코드가 있습니다.

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

판다에는 두 개의 서로 다른 데이터 프레임을 비교하고 데이터 기록에 대해 각 열에서 변경된 값을 반환하는 새로운 방법이 있습니다.

첫 번째 데이터 프레임

Id Customer Status      Date
1      ABC   Good  Mar 2023
2      BAC   Good  Feb 2024
3      CBA    Bad  Apr 2022

두 번째 데이터 프레임

Id Customer Status      Date
1      ABC    Bad  Mar 2023
2      BAC   Good  Feb 2024
5      CBA   Good  Apr 2024

데이터 프레임 비교

print("Dataframe difference -- \n")
print(df1.compare(df2))

print("Dataframe difference keeping equal values -- \n")
print(df1.compare(df2, keep_equal=True))

print("Dataframe difference keeping same shape -- \n")
print(df1.compare(df2, keep_shape=True))

print("Dataframe difference keeping same shape and equal values -- \n")
print(df1.compare(df2, keep_shape=True, keep_equal=True))

결과

Dataframe difference -- 

    Id       Status            Date          
  self other   self other      self     other
0  NaN   NaN   Good   Bad       NaN       NaN
2  3.0   5.0    Bad  Good  Apr 2022  Apr 2024

Dataframe difference keeping equal values -- 

    Id       Status            Date          
  self other   self other      self     other
0    1     1   Good   Bad  Mar 2023  Mar 2023
2    3     5    Bad  Good  Apr 2022  Apr 2024

Dataframe difference keeping same shape -- 

    Id       Customer       Status            Date          
  self other     self other   self other      self     other
0  NaN   NaN      NaN   NaN   Good   Bad       NaN       NaN
1  NaN   NaN      NaN   NaN    NaN   NaN       NaN       NaN
2  3.0   5.0      NaN   NaN    Bad  Good  Apr 2022  Apr 2024

Dataframe difference keeping same shape and equal values -- 

    Id       Customer       Status            Date          
  self other     self other   self other      self     other
0    1     1      ABC   ABC   Good   Bad  Mar 2023  Mar 2023
1    2     2      BAC   BAC   Good  Good  Feb 2024  Feb 2024
2    3     5      CBA   CBA    Bad  Good  Apr 2022  Apr 2024

승인된 답변 외에도, 저는 두 개의 데이터 프레임의 2D 세트 차이를 찾을 수 있는 더 넓은 솔루션을 제안하고 싶습니다.index/columns(두 데이터 이름 모두에 대해 일치하지 않을 수 있음).)▁for▁tolerance다▁also▁allows에 대한 허용오차를 설정할 수 .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]})

이 경우 위의 솔루션은 Empty DataFrame을 제공하며 대신 다음을 사용해야 합니다.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)

대칭 차이

데이터 프레임 중 하나에만 있고 둘 다에는 없는 행에 관심이 있는 경우 설정된 차이를 찾는 것입니다.

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

⚠️ 두 데이터 프레임에 중복이 없는 경우에만 작동합니다.

차이 설정 / 관계 대수 차이

이 있다면, 즉 세적차트차관있/경는이에심우이즉, df1-df2또는df1\df2:

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

⚠️ 두 데이터 프레임에 중복이 없는 경우에만 작동합니다.

이 있을 때 을 처리하는 ▁i다▁used▁dupl한▁when니icates▁with쪽▁handling▁so사습▁there▁i▁had▁on▁issues했용icates있▁dupl▁were▁and서▁at어▁side▁least에를 사용했습니다.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

기존 데이터 프레임의 인덱스를 변경할 필요가 없는 nice @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) 반합니다환을다▁in의 합니다.df1에도 .df2.
  • ~ (요소별 NOT)는를 부정하기 에, 는 앞요있는는논에부결다다가로과같니요져옵소를은음 (요소별 논리 NOT)에 있는 요소들을 df1 없는df2–둘 사이의 차이.
  • .dropna()이 있는 합니다.NaN 하는 것

참고 이것은 다음 경우에만 작동합니다.len(df1) >= len(df2).한다면df2.df1은 다음과 같은로 할 수 .df2[~df2.isin(df1)].dropna()

나는 찾았습니다.deepdiff라이브러리는 다른 세부사항이 필요하거나 주문 문제가 있는 경우 데이터 프레임으로 잘 확장되는 훌륭한 도구입니다.디핑을 실험할 수 있습니다.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]]}

또 다른 가능한 해결책은 다음과 같습니다.

df1[np.all(~np.all(df1.values == df2.values[:, None], axis=2), axis=0)]

출력:

    Name  Age
1   Mike   45
4  Marry   27
7   Bolt   39

람 함 를 수 필 있 수 니 다 습으로 행을 수 ._merge“left_only” 줄보꿰다의 .df1에서빠에서 빠진 .df2

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

사용해 보십시오.df_new = df1.merge(df2, how='outer', indicator=True).query('_merge == "left_only"').drop('_merge', 1)

df1에는 있지만 df2에는 없는 값이라는 차이를 가진 새 데이터 프레임이 생성됩니다.

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

반응형