it-swarm.com.de

Vergleichen von zwei Datenrahmen und Ermitteln der Unterschiede

Ich habe zwei Datenrahmen. Beispiele:

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

Jeder Datenrahmen hat das Datum als Index. Beide Datenrahmen haben die gleiche Struktur. 

Was ich tun möchte, ist, diese beiden Datenbilder zu vergleichen und herauszufinden, welche Zeilen in df2 sind und nicht in df1 sind. Ich möchte das Datum (Index) und die erste Spalte (Banane, Apple usw.) vergleichen, um zu sehen, ob sie in df2 vs df1 vorhanden sind.

Ich habe folgendes versucht:

Beim ersten Ansatz erhalte ich folgende Fehlermeldung: "Ausnahme: Kann nur identisch beschriftete DataFrame-Objekte vergleichen". Ich habe versucht, das Datum als Index zu entfernen, bekomme aber den gleichen Fehler.

Beim dritten Ansatz bekomme ich die Zusicherung, False zurückzugeben, kann aber nicht herausfinden, wie die verschiedenen Zeilen tatsächlich zu sehen sind.

Alle Hinweise wären willkommen

46
Eric D. Brown

Dieser Ansatz, df1 != df2, funktioniert nur für Datenrahmen mit identischen Zeilen und Spalten. Tatsächlich werden alle Datenrahmenachsen mit der _indexed_same-Methode verglichen, und es wird eine Ausnahme ausgelöst, wenn Unterschiede festgestellt werden, selbst in der Reihenfolge der Spalten/Indizes.

Wenn ich Sie richtig verstanden habe, möchten Sie keine Änderungen finden, sondern einen symmetrischen Unterschied. Ein Ansatz könnte dafür die Verkettung von Datenrahmen sein:

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

gruppiere nach 

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

index der eindeutigen Datensätze abrufen

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

filter

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

Wenn Sie die Datenrahmen an concat in einem Wörterbuch übergeben, wird ein Datenrahmen mit mehreren Indizes erstellt, aus dem Sie die Duplikate leicht löschen können. Dies führt zu einem Datenrahmen mit mehreren Indizes und den Unterschieden zwischen den Datenrahmen:

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)

Ergebnis:

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

Aufbauend auf Alkos Antwort, die fast für mich funktioniert hat, mit Ausnahme des Filterschritts (wo ich ValueError: cannot reindex from a duplicate axis bekomme), hier die letzte Lösung, die ich verwendet habe:

# 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]
3
fnl

Ich habe diese Lösung bekommen. Hilft Ihnen das?

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

ergebnis

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
1
eyquem
# 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
1
SpeedCoder5

Gründer hier eine einfache Lösung:

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

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

1
Tom2shoes

Ich habe diese Methode ausprobiert und es hat funktioniert. Ich hoffe es kann auch helfen:

"""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']]
0
debugging XD

Es gibt eine einfachere Lösung, die schneller und besser ist..... Und wenn sich die Zahlen unterscheiden, können sich sogar Mengenunterschiede ergeben:

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_'])

Hier ist df_diff eine Zusammenfassung der Unterschiede. Sie können sogar die Mengenunterschiede ermitteln. In deinem Beispiel:

 enter image description here

Erläuterung: Ähnlich wie beim Vergleich zweier Listen sollten wir sie zuerst ordnen und vergleichen, um sie effizient zu machen (das Konvertieren der Liste in Mengen/Hashing wäre ebenfalls schnell; beide sind eine unglaubliche Verbesserung des einfachen O (N ^ 2) doppelte Vergleichsschleife

Anmerkung: Der folgende Code erzeugt die Tabellen:

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'],
})
0
ntg

Ein wichtiges Detail ist, dass Ihre Daten doppelte Indexwerte aufweisen. Um einen direkten Vergleich durchzuführen, müssen wir alles mit df.reset_index() eindeutig machen. Daher können wir eine Auswahl anhand der Bedingungen vornehmen. Sobald in Ihrem Fall der Index definiert ist, gehe ich davon aus, dass Sie den Index beibehalten möchten, sodass es eine einzeilige Lösung gibt:

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

Sobald das Ziel aus Sicht von Pythonic darin besteht, die Lesbarkeit zu verbessern, können wir ein wenig brechen:

# 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)
0
gandreoti

Ich hoffe, das wäre für Sie nützlich. ^ 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
"""
0
Carson Arucard