Finden Sie den Unterschied zwischen zwei Datenrahmen

Lesezeit: 6 Minuten

Benutzeravatar von userPyGeo
BenutzerPyGeo

Ich habe zwei Datenrahmen df1 und df2, wobei df2 eine Teilmenge von df1 ist. Wie erhalte ich einen neuen Datenrahmen (df3), der der Unterschied zwischen den beiden Datenrahmen ist?

Mit anderen Worten, ein Datenrahmen, der alle Zeilen/Spalten in df1 hat, die nicht in df2 sind?

Geben Sie hier die Bildbeschreibung ein

  • Der einfachste Weg, dies zu tun, hängt davon ab, wie Ihre Datenrahmen strukturiert sind (dh ob die Indizes verwendet werden können usw.). Dies ist ein gutes Beispiel dafür, warum Sie in Pandas-Fragen immer ein reproduzierbares Beispiel einfügen sollten.

    – cmaher

    6. Februar 2018 um 16:30 Uhr

  • Ich habe das Dataframe-Beispielbild hinzugefügt

    – BenutzerPyGeo

    6. Februar 2018 um 16:33 Uhr

  • ähnlich wie stackoverflow.com/q/20225110

    – SpeedCoder5

    7. Juni 2018 um 13:48 Uhr

Benutzeravatar von BENY
BENY

Durch die Nutzung 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]})

Es wird wie unten ausgegeben, was falsch ist

Falsche Ausgabe:

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

Richtige Ausgabe

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

Wie erreicht man das?

Methode 1: Verwenden isin mit tuple

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

Methode 2: merge mit 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

  • Sie können auch festlegen, welche Spalten bei der Suche nach Duplikaten berücksichtigt werden sollen: pd.concat([df1,df2]).drop_duplicates(subset = ['col1','col2'], keep=False)

    – Szpaqn

    8. Januar 2019 um 8:15 Uhr

  • @Szpaqn Beachten Sie, dass diese Methode den Sonderfall nicht behandelt. 🙂

    – BENY

    9. Januar 2019 um 17:10 Uhr

  • @DtechNet Sie müssen dafür sorgen, dass zwei Datenrahmen denselben Namen haben

    – BENY

    16. Oktober 2019 um 20:14 Uhr

  • Methode 2 (indicator=True) ist ein sehr vielseitiges und nützliches Werkzeug, ich würde es gerne oben in dieser Antwort sehen, aber mit ‘outer’ nicht ‘left’ join, um alle 3 Situationen abzudecken.

    – mirekphd

    2. Mai 2020 um 11:07 Uhr

  • Könnten Sie bitte die Bedeutung von erklären apply(tuple,1) ?

    – Lingli

    29. Mai 2020 um 4:22 Uhr

Benutzeravatar von jpp
jpp

Versuchen Sie für Zeilen dies, wo Name ist die gemeinsame Indexspalte (kann eine Liste für mehrere gemeinsame Spalten sein oder angeben left_on und right_on):

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

Das indicator=True Die Einstellung ist nützlich, da sie eine Spalte namens hinzufügt _mergemit allen Änderungen dazwischen df1 und df2kategorisiert in 3 mögliche Arten: “left_only”, “right_only” oder “both”.

Versuchen Sie Folgendes für Spalten:

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

  • Möchte der Downvoter einen Kommentar abgeben? merge mit indicator=True ist die klassische Lösung zum Vergleichen von Datenrahmen anhand bestimmter Felder.

    – jpp

    8. Januar 2019 um 9:17 Uhr

Benutzeravatar von toecsnar42
toecsnar42

Akzeptierte Antwort Methode 1 funktioniert nicht für Datenrahmen mit NaNs im Inneren, wie pd.np.nan != pd.np.nan. Ich bin mir nicht sicher, ob dies der beste Weg ist, aber es kann vermieden werden

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

Es ist langsamer, weil es Daten in Zeichenfolgen umwandeln muss, aber dank dieses Umwandelns pd.np.nan == pd.np.nan.

Gehen wir den Code durch. Zuerst wandeln wir Werte in Zeichenfolgen um und wenden sie an tuple Funktion für jede Zeile.

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

Dank dessen bekommen wir pd.Series Objekt mit Liste von Tupeln. Jedes Tupel enthält ganze Zeilen von df1/df2. Dann bewerben wir uns isin Methode an df1 um zu prüfen, ob jedes Tupel “in” ist df2. Das Ergebnis ist pd.Series mit booleschen Werten. True, wenn Tupel von df1 ist in df2. Am Ende negieren wir Ergebnisse mit ~ unterzeichnen und Filter anwenden df1. Lange Rede kurzer Sinn, wir bekommen nur diese Zeilen von df1 die sind nicht drin df2.

Um es lesbarer zu machen, können wir es schreiben als:

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]

  • Dies ist eine großartige Antwort, aber sie ist als Einzeiler unverständlich. Wenn man jeden Schritt trennt und versteht, was er tut, wird sehr klar, wie er die Arbeit erledigt.

    – rioZg

    10. Februar 2021 um 9:52 Uhr


  • Erklärung hinzugefügt. Ich hoffe, es hilft!

    – toecsnar42

    17. Februar 2021 um 22:19 Uhr

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

Benutzeravatar von Cherif Diallo
Cherif Diallo

Vielleicht ein einfacherer Einzeiler mit identischen oder unterschiedlichen Spaltennamen. Funktionierte auch bei df2[‘Name2’] enthielt doppelte Werte.

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

  • einfach und effektiv. „errors=’ignore“ hinzugefügt, um das Problem zu lösen, wenn die Zielwerte nicht in der Quelle sind (dh Schnittmenge) und das Zurücksetzen des Index am Ende ein df ergibt, das dem Original ähnlich ist.

    – HerrE

    3. Februar 2020 um 3:50 Uhr

Benutzeravatar von VirtualScooter
VirtualScooter

edit2, ich habe eine neue Lösung gefunden, ohne den Index setzen zu müssen

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

Okay, ich fand, dass die Antwort mit der höchsten Stimme bereits das enthält, was ich herausgefunden habe. Ja, wir können diesen Code nur unter der Bedingung verwenden, dass es keine Duplikate in jeweils zwei dfs gibt.


Ich habe eine knifflige Methode. Zuerst setzen wir ‘Name’ als Index von zwei Datenrahmen, die durch die Frage angegeben werden. Da wir in zwei dfs den gleichen ‘Namen’ haben, können wir den Index des ‘kleineren’ df einfach aus dem ‘größeren’ df löschen. Hier ist der Code.

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

  • einfach und effektiv. „errors=’ignore“ hinzugefügt, um das Problem zu lösen, wenn die Zielwerte nicht in der Quelle sind (dh Schnittmenge) und das Zurücksetzen des Index am Ende ein df ergibt, das dem Original ähnlich ist.

    – HerrE

    3. Februar 2020 um 3:50 Uhr

Benutzeravatar von Yushan ZHANG
Yushan ZHANG

Pandas bietet jetzt a neue API Datenrahmen Diff zu tun: pandas.DataFrame.compare

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

1436170cookie-checkFinden Sie den Unterschied zwischen zwei Datenrahmen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy