Pandas erhalten Zeilen, die sich NICHT in einem anderen Datenrahmen befinden

Lesezeit: 8 Minuten

Benutzer-Avatar
schöne Dinge denken

Ich habe zwei Pandas-Datenrahmen, die einige Zeilen gemeinsam haben.

Angenommen, dataframe2 ist eine Teilmenge von dataframe1.

Wie kann ich die Zeilen von dataframe1 abrufen, die sich nicht in dataframe2 befinden?

df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5], 'col2' : [10, 11, 12, 13, 14]}) 
df2 = pandas.DataFrame(data = {'col1' : [1, 2, 3], 'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

df2

   col1  col2
0     1    10
1     2    11
2     3    12

Erwartetes Ergebnis:

   col1  col2
3     4    13
4     5    14

  • @TedPetrou Ich verstehe nicht, wie die von Ihnen gegebene Antwort richtig ist. Wenn ich zwei Datenrahmen habe, von denen einer eine Teilmenge des anderen ist, muss ich alle Zeilen entfernen, die sich in der Teilmenge befinden. Ich möchte keine Duplikate entfernen. Ich möchte die Teilmenge vollständig entfernen.

    – Musikbox

    16. Mai 2019 um 7:38 Uhr

  • Mögliches Duplikat des Löschens von Zeilen aus dem Datenrahmen basierend auf einer „nicht in“-Bedingung

    – Jim G.

    11. September 2019 um 18:33 Uhr

Benutzer-Avatar
Ted Petrou

Die aktuell ausgewählte Lösung liefert falsche Ergebnisse. Um dieses Problem korrekt zu lösen, können wir einen Left-Join von ausführen df1 zu df2stellen Sie sicher, dass Sie zuerst nur die eindeutigen Zeilen für erhalten df2.

Zuerst müssen wir den ursprünglichen DataFrame ändern, um die Zeile mit Daten hinzuzufügen [3, 10].

df1 = pd.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 
                           'col2' : [10, 11, 12, 13, 14, 10]}) 
df2 = pd.DataFrame(data = {'col1' : [1, 2, 3],
                           'col2' : [10, 11, 12]})

df1

   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14
5     3    10

df2

   col1  col2
0     1    10
1     2    11
2     3    12

Führen Sie eine Linksverknüpfung durch und eliminieren Sie Duplikate df2 so dass jede Reihe von df1 verbindet sich mit genau 1 Reihe von df2. Verwenden Sie den Parameter indicator um eine zusätzliche Spalte zurückzugeben, die angibt, aus welcher Tabelle die Zeile stammt.

df_all = df1.merge(df2.drop_duplicates(), on=['col1','col2'], 
                   how='left', indicator=True)
df_all

   col1  col2     _merge
0     1    10       both
1     2    11       both
2     3    12       both
3     4    13  left_only
4     5    14  left_only
5     3    10  left_only

Erstellen Sie eine boolesche Bedingung:

df_all['_merge'] == 'left_only'

0    False
1    False
2    False
3     True
4     True
5     True
Name: _merge, dtype: bool

Warum andere Lösungen falsch sind

Einige Lösungen machen den gleichen Fehler – sie prüfen nur, ob jeder Wert unabhängig voneinander in jeder Spalte steht, nicht zusammen in derselben Zeile. Hinzufügen der letzten Zeile, die eindeutig ist, aber die Werte aus beiden Spalten enthält df2 deckt den Fehler auf:

common = df1.merge(df2,on=['col1','col2'])
(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))
0    False
1    False
2    False
3     True
4     True
5    False
dtype: bool

Diese Lösung liefert das gleiche falsche Ergebnis:

df1.isin(df2.to_dict('l')).all(1)

  • aber ich nehme an, sie gingen davon aus, dass col1 eindeutig ist und ein Index ist (in der Frage nicht erwähnt, aber offensichtlich). Wenn es also niemals einen solchen Fall gibt, in dem es zwei Werte von col2 für denselben Wert von col1 gibt (es kann nicht zwei Spalten col1=3 geben), sind die obigen Antworten korrekt.

    – paschut

    6. November 2017 um 8:38 Uhr

  • Es ist sicherlich nicht offensichtlich, also ist Ihr Punkt ungültig. Meine Lösung lässt sich auf mehr Fälle verallgemeinern.

    – Ted Petrou

    6. November 2017 um 13:54 Uhr

  • Frage, wäre es nicht einfacher, ein Slice als ein boolesches Array zu erstellen? Da das Ziel darin besteht, die Zeilen zu erhalten.

    – Matías Romo

    20. Februar 2019 um 2:50 Uhr

  • Verwenden df_all[df_all['_merge'] == 'left_only'] um ein df mit den Ergebnissen zu haben

    – gies0r

    15. Mai 2019 um 9:38 Uhr

  • Für Neuankömmlinge ist das Hinzufügen der zusätzlichen Zeile ohne Erklärung verwirrend. Dann macht @gies0r diese Lösung besser. Außerdem würde ich vorschlagen, zu verwenden how='outer' so, dass die _merge Spalte hat links/rechts/beide, was verständlicher ist, wenn zukünftige Leser versuchen, die Lösung auf ihre Probleme anzuwenden.

    – Yeliabsalohcin

    9. September 2021 um 14:46 Uhr

Benutzer-Avatar
EdChum

Eine Methode wäre, das Ergebnis einer inneren Zusammenführung aus beiden dfs zu speichern, dann können wir einfach die Zeilen auswählen, wenn die Werte einer Spalte nicht so gemeinsam sind:

In [119]:

common = df1.merge(df2,on=['col1','col2'])
print(common)
df1[(~df1.col1.isin(common.col1))&(~df1.col2.isin(common.col2))]
   col1  col2
0     1    10
1     2    11
2     3    12
Out[119]:
   col1  col2
3     4    13
4     5    14

BEARBEITEN

Eine andere Methode, wie Sie gefunden haben, ist die Verwendung isin die produzieren wird NaN Zeilen, die Sie löschen können:

In [138]:

df1[~df1.isin(df2)].dropna()
Out[138]:
   col1  col2
3     4    13
4     5    14

Wenn df2 Zeilen jedoch nicht auf die gleiche Weise startet, funktioniert dies nicht:

df2 = pd.DataFrame(data = {'col1' : [2, 3,4], 'col2' : [11, 12,13]})

wird das gesamte df erzeugen:

In [140]:

df1[~df1.isin(df2)].dropna()
Out[140]:
   col1  col2
0     1    10
1     2    11
2     3    12
3     4    13
4     5    14

  • df1[~df1.isin(df2)].dropna(how = 'all') scheint den Trick zu tun. Trotzdem danke – Ihre Antwort hat mir geholfen, eine Lösung zu finden.

    – schöne Dinge denken

    6. März 2015 um 15:48 Uhr

  • Würden Sie gerne erklären, was ~ tut in Ihrem Code df1[~df1.isin(df2)] bitte? Kann nichts daraus googeln, da es nur ein Symbol ist. Vielen Dank.

    – Bowen Liu

    29. Oktober 2018 um 16:03 Uhr

  • @BowenLiu es negiert den Ausdruck, im Grunde heißt es, wählen Sie alle aus, die NICHT IN statt IN sind.

    – Weg

    24. August 2020 um 11:25 Uhr

  • @thinknicethings, es könnte einfacher sein: df1[~df1.index.isin(df2.index)]

    – Gill Bates

    5. Juni 2021 um 9:13 Uhr


Unter der Annahme, dass die Indizes in den Datenrahmen konsistent sind (ohne Berücksichtigung der tatsächlichen Spaltenwerte):

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

Benutzer-Avatar
Rune Lyngsoe

Wie bereits angedeutet, erfordert isin für eine Übereinstimmung, dass Spalten und Indizes gleich sind. Wenn nur der Zeileninhalt übereinstimmen soll, besteht eine Möglichkeit, die Maske zum Filtern der vorhandenen Zeilen zu erhalten, darin, die Zeilen in einen (Multi-)Index umzuwandeln:

In [77]: df1 = pandas.DataFrame(data = {'col1' : [1, 2, 3, 4, 5, 3], 'col2' : [10, 11, 12, 13, 14, 10]})
In [78]: df2 = pandas.DataFrame(data = {'col1' : [1, 3, 4], 'col2' : [10, 12, 13]})
In [79]: df1.loc[~df1.set_index(list(df1.columns)).index.isin(df2.set_index(list(df2.columns)).index)]
Out[79]:
   col1  col2
1     2    11
4     5    14
5     3    10

Wenn der Index berücksichtigt werden soll, hat set_index das Schlüsselwortargument append, um Spalten an den vorhandenen Index anzuhängen. Wenn Spalten nicht ausgerichtet sind, kann list(df.columns) durch Spaltenspezifikationen ersetzt werden, um die Daten auszurichten.

pandas.MultiIndex.from_tuples(df<N>.to_records(index = False).tolist())

könnte alternativ verwendet werden, um die Indizes zu erstellen, obwohl ich bezweifle, dass dies effizienter ist.

Benutzer-Avatar
Pragalbh kulshrestha

Angenommen, Sie haben zwei Datenrahmen, df_1 und df_2 mit mehreren Feldern (Spaltennamen), und Sie möchten anhand einiger Felder (z. B. fields_x, fields_y) nur die Einträge in df_1 finden, die nicht in df_2 enthalten sind. Führen Sie die folgenden Schritte aus.

Schritt 1. Fügen Sie jeweils eine Spalte key1 und key2 zu df_1 und df_2 hinzu.

Schritt 2. Führen Sie die Datenrahmen wie unten gezeigt zusammen. field_x und field_y sind unsere gewünschten Spalten.

Schritt 3. Wählen Sie nur die Zeilen aus df_1 aus, in denen Schlüssel1 nicht gleich Schlüssel2 ist.

Step4.Drop key1 und key2.

Diese Methode löst Ihr Problem und funktioniert auch bei großen Datensätzen schnell. Ich habe es für Datenrahmen mit mehr als 1.000.000 Zeilen ausprobiert.

df_1['key1'] = 1
df_2['key2'] = 1
df_1 = pd.merge(df_1, df_2, on=['field_x', 'field_y'], how = 'left')
df_1 = df_1[~(df_1.key2 == df_1.key1)]
df_1 = df_1.drop(['key1','key2'], axis=1)

  • Ich glaube nicht, dass dies technisch gesehen das ist, was er will – er möchte wissen, welche Zeilen für welche df eindeutig waren. aber ich denke, diese Lösung gibt einen df von Zeilen zurück, die entweder für den ersten df oder den zweiten df eindeutig waren.

    – MetaStack

    30. August 2016 um 20:37 Uhr

Benutzer-Avatar
Hamza

Dies ist der beste Weg, es zu tun:

df = df1.drop_duplicates().merge(df2.drop_duplicates(), on=df2.columns.to_list(), 
                   how='left', indicator=True)
df.loc[df._merge=='left_only',df.columns!='_merge']

Beachten Sie, dass dupliziertes Löschen verwendet wird, um die Vergleiche zu minimieren. Es würde auch ohne sie funktionieren. Der beste Weg ist, die Zeileninhalte selbst zu vergleichen und nicht den Index oder eine/zwei Spalten, und derselbe Code kann auch für andere Filter wie „both“ und „right_only“ verwendet werden, um ähnliche Ergebnisse zu erzielen. Für diese Syntax können Datenrahmen eine beliebige Anzahl von Spalten und sogar unterschiedliche Indizes haben. Nur die Spalten sollten in beiden Datenrahmen vorkommen.

Warum ist dies der beste Weg?

  1. index.difference funktioniert nur für eindeutige indexbasierte Vergleiche
  2. pandas.concat() zusammen mit drop_duplicated() ist nicht ideal, da es auch die Zeilen entfernt, die sich möglicherweise nur in dem Datenrahmen befinden, den Sie behalten möchten, und aus triftigen Gründen dupliziert werden.

  • Ich glaube nicht, dass dies technisch gesehen das ist, was er will – er möchte wissen, welche Zeilen für welche df eindeutig waren. aber ich denke, diese Lösung gibt einen df von Zeilen zurück, die entweder für den ersten df oder den zweiten df eindeutig waren.

    – MetaStack

    30. August 2016 um 20:37 Uhr

Benutzer-Avatar
Gemeinschaft

ein bisschen spät, aber es könnte sich lohnen, den Parameter “indicator” von pd.merge zu überprüfen.

Ein Beispiel finden Sie in dieser anderen Frage: Vergleichen Sie PandaS DataFrames und geben Sie Zeilen zurück, die in der ersten fehlen

  • Ja! Auch hier: stackoverflow.com/questions/49487263/…

    – Dan

    3. April 2019 um 7:00 Uhr

1093400cookie-checkPandas erhalten Zeilen, die sich NICHT in einem anderen Datenrahmen befinden

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

Privacy policy