Programing

두 데이터 프레임을 비교하고 차이점 얻기

lottogame 2020. 12. 5. 09:11
반응형

두 데이터 프레임을 비교하고 차이점 얻기


두 개의 데이터 프레임이 있습니다. 예 :

df1:
Date       Fruit  Num  Color 
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange  8.6 Orange
2013-11-24 Apple   7.6 Green
2013-11-24 Celery 10.2 Green

df2:
Date       Fruit  Num  Color 
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange  8.6 Orange
2013-11-24 Apple   7.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25 Apple  22.1 Red
2013-11-25 Orange  8.6 Orange

각 데이터 프레임에는 날짜가 인덱스로 있습니다. 두 데이터 프레임은 동일한 구조를 가지고 있습니다.

내가하고 싶은 것은이 두 데이터 프레임을 비교하고 df1에없는 df2에있는 행을 찾는 것입니다. 날짜 (인덱스)와 첫 번째 열 (Banana, APple 등)을 비교하여 df2와 df1에 존재하는지 확인하고 싶습니다.

나는 다음을 시도했다 :

첫 번째 방법에서는 "예외 : 레이블이 동일한 DataFrame 개체 만 비교할 수 있습니다"라는 오류가 발생 합니다 . 날짜를 인덱스로 제거하려고 시도했지만 동일한 오류가 발생합니다.

세 번째 방법 , 나는 False를 반환하기 위해 어설 수 있지만, 실제로 다른 행을 참조하는 방법을 알아낼 수 없습니다.

모든 포인터를 환영합니다


이 접근 방식 df1 != df2은 행과 열이 동일한 데이터 프레임에서만 작동합니다. 실제로 모든 데이터 프레임 축은 _indexed_same메서드 와 비교 되며 열 / 인덱스 순서에서도 차이가 발견되면 예외가 발생합니다.

내가 당신을 맞았다면, 당신은 변화가 아니라 대칭적인 차이를 찾고 싶어합니다. 이를 위해 한 가지 접근 방식은 데이터 프레임을 연결하는 것입니다.

>>> df = pd.concat([df1, df2])
>>> df = df.reset_index(drop=True)

그룹화

>>> df_gpby = df.groupby(list(df.columns))

고유 레코드 색인 가져 오기

>>> idx = [x[0] for x in df_gpby.groups.values() if len(x) == 1]

필터

>>> df.reindex(idx)
         Date   Fruit   Num   Color
9  2013-11-25  Orange   8.6  Orange
8  2013-11-25   Apple  22.1     Red

데이터 프레임을 전달하여 사전에 연결하면 중복 항목을 쉽게 삭제할 수있는 다중 인덱스 데이터 프레임이 생성되어 데이터 프레임 간의 차이가있는 다중 인덱스 데이터 프레임이 생성됩니다.

import sys
if sys.version_info[0] < 3:
    from StringIO import StringIO
else:
    from io import StringIO
import pandas as pd

DF1 = StringIO("""Date       Fruit  Num  Color 
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange  8.6 Orange
2013-11-24 Apple   7.6 Green
2013-11-24 Celery 10.2 Green
""")
DF2 = StringIO("""Date       Fruit  Num  Color 
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange  8.6 Orange
2013-11-24 Apple   7.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25 Apple  22.1 Red
2013-11-25 Orange  8.6 Orange""")


df1 = pd.read_table(DF1, sep='\s+')
df2 = pd.read_table(DF2, sep='\s+')
#%%
dfs_dictionary = {'DF1':df1,'DF2':df2}
df=pd.concat(dfs_dictionary)
df.drop_duplicates(keep=False)

결과:

             Date   Fruit   Num   Color
DF2 4  2013-11-25   Apple  22.1     Red
    5  2013-11-25  Orange   8.6  Orange

필터링 단계 (내가 얻는 곳 :)를 제외하고 거의 나를 위해 거의 효과가 있었던 alko의 대답을 기반 ValueError: cannot reindex from a duplicate axis으로 한 최종 솔루션은 다음과 같습니다.

# join the dataframes
united_data = pd.concat([data1, data2, data3, ...])
# group the data by the whole row to find duplicates
united_data_grouped = united_data.groupby(list(united_data.columns))
# detect the row indices of unique rows
uniq_data_idx = [x[0] for x in united_data_grouped.indices.values() if len(x) == 1]
# extract those unique values
uniq_data = united_data.iloc[uniq_data_idx]

더 빠르고 더 나은 더 간단한 솔루션이 있으며, 숫자가 다르면 수량 차이를 줄 수도 있습니다.

df1_i = df1.set_index(['Date','Fruit','Color'])
df2_i = df2.set_index(['Date','Fruit','Color'])
df_diff = df1_i.join(df2_i,how='outer',rsuffix='_').fillna(0)
df_diff = (df_diff['Num'] - df_diff['Num_'])

여기서 df_diff는 차이점의 개요입니다. 수량 차이를 찾기 위해 사용할 수도 있습니다. 귀하의 예에서 :

여기에 이미지 설명 입력

설명 : 두 목록을 비교하는 것과 마찬가지로 효율적으로 수행하려면 먼저 순서를 지정한 다음 비교해야합니다 (목록을 세트 / 해싱으로 변환하는 것도 빠릅니다. 둘 다 단순한 O (N ^ 2) 이중 비교 루프에 대한 놀라운 개선입니다)

참고 : 다음 코드는 테이블을 생성합니다.

df1=pd.DataFrame({
    'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'],
    'Fruit':['Banana','Orange','Apple','Celery'],
    'Num':[22.1,8.6,7.6,10.2],
    'Color':['Yellow','Orange','Green','Green'],
})
df2=pd.DataFrame({
    'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'],
    'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'],
    'Num':[22.1,8.6,7.6,10.2,22.1,8.6],
    'Color':['Yellow','Orange','Green','Green','Red','Orange'],
})

# given
df1=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'],
    'Fruit':['Banana','Orange','Apple','Celery'],
    'Num':[22.1,8.6,7.6,10.2],
    'Color':['Yellow','Orange','Green','Green']})
df2=pd.DataFrame({'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'],
    'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'],
    'Num':[22.1,8.6,7.6,1000,22.1,8.6],
    'Color':['Yellow','Orange','Green','Green','Red','Orange']})

# find which rows are in df2 that aren't in df1 by Date and Fruit
df_2notin1 = df2[~(df2['Date'].isin(df1['Date']) & df2['Fruit'].isin(df1['Fruit']) )].dropna().reset_index(drop=True)

# output
print('df_2notin1\n', df_2notin1)
#      Color        Date   Fruit   Num
# 0     Red  2013-11-25   Apple  22.1
# 1  Orange  2013-11-25  Orange   8.6

이 솔루션을 얻었습니다. 도움이 되나요?

text = """df1:
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green

df2:
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25 Apple 22.1 Red
2013-11-25 Orange 8.6 Orange



argetz45
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 118.6 Orange
2013-11-24 Apple 74.6 Green
2013-11-24 Celery 10.2 Green
2013-11-25     Nuts    45.8 Brown
2013-11-25 Apple 22.1 Red
2013-11-25 Orange 8.6 Orange
2013-11-26   Pear 102.54    Pale"""

.

from collections import OrderedDict
import re

r = re.compile('([a-zA-Z\d]+).*\n'
               '(20\d\d-[01]\d-[0123]\d.+\n?'
               '(.+\n?)*)'
               '(?=[ \n]*\Z'
                  '|'
                  '\n+[a-zA-Z\d]+.*\n'
                  '20\d\d-[01]\d-[0123]\d)')

r2 = re.compile('((20\d\d-[01]\d-[0123]\d) +([^\d.]+)(?<! )[^\n]+)')

d = OrderedDict()
bef = []

for m in r.finditer(text):
    li = []
    for x in r2.findall(m.group(2)):
        if not any(x[1:3]==elbef for elbef in bef):
            bef.append(x[1:3])
            li.append(x[0])
    d[m.group(1)] = li


for name,lu in d.iteritems():
    print '%s\n%s\n' % (name,'\n'.join(lu))

결과

df1
2013-11-24 Banana 22.1 Yellow
2013-11-24 Orange 8.6 Orange
2013-11-24 Apple 7.6 Green
2013-11-24 Celery 10.2 Green

df2
2013-11-25 Apple 22.1 Red
2013-11-25 Orange 8.6 Orange

argetz45
2013-11-25     Nuts    45.8 Brown
2013-11-26   Pear 102.54    Pale

여기에 간단한 솔루션을 설립하십시오.

https://stackoverflow.com/a/47132808/9656339

pd.concat([df1, df2]).loc[df1.index.symmetric_difference(df2.index)]


업데이트하고 배치하면 다른 사람들이 쉽게 찾을 수있는 곳에 위의 배심원 의 답변에 대한 ling 의 의견이 있습니다.

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

다음 데이터 프레임으로 테스트 :

df1=pd.DataFrame({
    'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24'],
    'Fruit':['Banana','Orange','Apple','Celery'],
    'Num':[22.1,8.6,7.6,10.2],
    'Color':['Yellow','Orange','Green','Green'],
})

df2=pd.DataFrame({
    'Date':['2013-11-24','2013-11-24','2013-11-24','2013-11-24','2013-11-25','2013-11-25'],
    'Fruit':['Banana','Orange','Apple','Celery','Apple','Orange'],
    'Num':[22.1,8.6,7.6,10.2,22.1,8.6],
    'Color':['Yellow','Orange','Green','Green','Red','Orange'],
})

결과 : 여기에 이미지 설명 입력


주의해야 할 한 가지 중요한 세부 사항은 데이터에 중복 인덱스 값 이 있다는 것입니다 . 따라서 간단한 비교를 수행하려면 모든 항목을 고유하게 설정해야 df.reset_index()하므로 조건에 따라 선택을 수행 할 수 있습니다. 귀하의 경우 색인이 정의되면 색인을 유지하고 싶으므로 한 줄짜리 솔루션이 있다고 가정합니다.

[~df2.reset_index().isin(df1.reset_index())].dropna().set_index('Date')

파이썬 적 관점에서 목표가 가독성을 높이는 것이라면, 우리는 조금 깰 수 있습니다 :

# keep the index name, if it does not have a name it uses the default name
index_name = df.index.name if df.index.name else 'index' 

# setting the index to become unique
df1 = df1.reset_index()
df2 = df2.reset_index()

# getting the differences to a Dataframe
df_diff = df2[~df2.isin(df1)].dropna().set_index(index_name)

이것이 당신에게 유용하기를 바랍니다. ^ o ^

df1 = pd.DataFrame({'date': ['0207', '0207'], 'col1': [1, 2]})
df2 = pd.DataFrame({'date': ['0207', '0207', '0208', '0208'], 'col1': [1, 2, 3, 4]})
print(f"df1(Before):\n{df1}\ndf2:\n{df2}")
"""
df1(Before):
   date  col1
0  0207     1
1  0207     2

df2:
   date  col1
0  0207     1
1  0207     2
2  0208     3
3  0208     4
"""

old_set = set(df1.index.values)
new_set = set(df2.index.values)
new_data_index = new_set - old_set
new_data_list = []
for idx in new_data_index:
    new_data_list.append(df2.loc[idx])

if len(new_data_list) > 0:
    df1 = df1.append(new_data_list)
print(f"df1(After):\n{df1}")
"""
df1(After):
   date  col1
0  0207     1
1  0207     2
2  0208     3
3  0208     4
"""

이 방법을 시도해 보았는데 효과가있었습니다. 도움이되기를 바랍니다.

"""Identify differences between two pandas DataFrames"""
df1.sort_index(inplace=True)
df2.sort_index(inplace=True)
df_all = pd.concat([df1, df12], axis='columns', keys=['First', 'Second'])
df_final = df_all.swaplevel(axis='columns')[df1.columns[1:]]
df_final[df_final['change this to one of the columns'] != df_final['change this to one of the columns']]

참고 URL : https://stackoverflow.com/questions/20225110/comparing-two-dataframes-and-getting-the-differences

반응형