LEFT
| RIGHT
| FULL
) (INNER
| OUTER
) Verbindung mit Pandas durch?merge
? join
? concat
? update
? Wer? Was? Warum?!... und mehr. Ich habe diese wiederkehrenden Fragen zu verschiedenen Aspekten der pandas Merge-Funktionalität gesehen. Die meisten Informationen zu Merge und seinen verschiedenen Anwendungsfällen sind heute auf Dutzende falsch formulierter, nicht durchsuchbarer Posts verteilt. Ziel ist es, einige der wichtigsten Punkte für die Nachwelt zusammenzufassen.
Diese QnA ist als nächster Teil einer Reihe hilfreicher Benutzerhandbücher zu allgemeinen pandas Redewendungen gedacht (siehe dieser Beitrag zum Pivoting und dieser Beitrag zur Verkettung) , worauf ich später noch eingehen werde).
Bitte beachte, dass dieser Beitrag nicht als Ersatz für Dokumentation gedacht ist, also lies das bitte auch! Einige der Beispiele stammen von dort.
Dieser Beitrag zielt darauf ab, den Lesern eine Einführung in das Zusammenführen mit Pandas zu geben, wie man es benutzt und wann man es nicht benutzt.
Im Einzelnen wird dieser Beitrag wie folgt behandelt:
Die Grundlagen - Arten von Verknüpfungen (LINKS, RECHTS, AUSSEN, INNEN)
merge
und join
Was dieser Beitrag nicht durchlaufen wird:
Hinweis
Die meisten Beispiele verwenden standardmäßig INNER JOIN-Vorgänge, während verschiedene Funktionen demonstriert werden, sofern nicht anders angegeben.Außerdem können hier alle DataFrames kopiert und repliziert werden, damit Sie damit spielen können. Lesen Sie auch dieser Beitrag , wie Sie DataFrames aus Ihrer Zwischenablage lesen.
Zuletzt wurden alle visuellen Darstellungen von JOIN-Vorgängen mit Google Drawings von Hand gezeichnet. Inspiration von hier .
merge
benutzt!Setup
np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})
left
key value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right
key value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
Der Einfachheit halber trägt die Schlüsselspalte (vorerst) den gleichen Namen.
Ein INNER JOIN wird dargestellt durch
Hinweis
Zusammen mit den kommenden Zahlen folgen alle dieser Konvention:
- Blau zeigt Zeilen an, die im Zusammenführungsergebnis vorhanden sind
- rot kennzeichnet Zeilen, die vom Ergebnis ausgeschlossen (d. h. entfernt) sind
- grün zeigt fehlende Werte an, die im Ergebnis durch NaNs ersetzt werden
Rufen Sie pd.merge
auf, um einen INNER JOIN auszuführen, und geben Sie den linken DataFrame, den rechten DataFrame und den Verknüpfungsschlüssel an.
pd.merge(left, right, on='key')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
Dies gibt nur Zeilen von left
und right
zurück, die einen gemeinsamen Schlüssel haben (in diesem Beispiel "B" und "D").
In neueren Versionen von pandas (v0.21 oder so) ist merge
jetzt eine Funktion erster Ordnung, sodass Sie DataFrame.merge
aufrufen können.
left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
Ein LEFT OUTER JOIN oder LEFT JOIN wird durch dargestellt
Dies kann durch Angabe von how='left'
erfolgen.
left.merge(right, on='key', how='left')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
Beachten Sie hier die Platzierung der NaNs. Wenn Sie how='left'
angeben, werden nur Schlüssel aus left
verwendet und fehlende Daten aus right
werden durch NaN ersetzt.
Und in ähnlicher Weise für einen RIGHT OUTER JOIN oder RIGHT JOIN der ist ...
... how='right'
angeben:
left.merge(right, on='key', how='right')
key value_x value_y
0 B 0.400157 1.867558
1 D 2.240893 -0.977278
2 E NaN 0.950088
3 F NaN -0.151357
Hier werden Schlüssel aus right
verwendet, und fehlende Daten aus left
werden durch NaN ersetzt.
Schließlich für die FULL OUTER JOIN , gegeben durch
gib how='outer'
an.
left.merge(right, on='key', how='outer')
key value_x value_y
0 A 1.764052 NaN
1 B 0.400157 1.867558
2 C 0.978738 NaN
3 D 2.240893 -0.977278
4 E NaN 0.950088
5 F NaN -0.151357
Dies verwendet die Schlüssel aus beiden Frames und NaNs werden für fehlende Zeilen in beiden eingefügt.
Die Dokumentation fasst diese verschiedenen Zusammenführungen gut zusammen:
Wenn Sie LINKS-ausschließende JOINs und RECHTS-ausschließende JOINs in zwei benötigen Schritte.
Für LEFT-Excluding JOIN, dargestellt als
Führen Sie zunächst einen LEFT OUTER JOIN durch und filtern Sie dann (ohne!) Zeilen, die nur aus left
stammen.
(left.merge(right, on='key', how='left', indicator=True)
.query('_merge == "left_only"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
Wo,
left.merge(right, on='key', how='left', indicator=True)
key value_x value_y _merge
0 A 1.764052 NaN left_only
1 B 0.400157 1.867558 both
2 C 0.978738 NaN left_only
3 D 2.240893 -0.977278 both
Und in ähnlicher Weise, für einen RECHTS-ausschließenden JOIN,
(left.merge(right, on='key', how='right', indicator=True)
.query('_merge == "right_only"')
.drop('_merge', 1))
key value_x value_y
2 E NaN 0.950088
3 F NaN -0.151357
Zuletzt, wenn Sie eine Zusammenführung durchführen müssen, bei der nur die Schlüssel von links oder rechts beibehalten werden, aber nicht beide (IOW, Ausführen eines ANTI-JOIN ) ,
Sie können dies auf ähnliche Weise tun -
(left.merge(right, on='key', how='outer', indicator=True)
.query('_merge != "both"')
.drop('_merge', 1))
key value_x value_y
0 A 1.764052 NaN
2 C 0.978738 NaN
4 E NaN 0.950088
5 F NaN -0.151357
Wenn die Schlüsselspalten unterschiedlich benannt sind, z. B. left
hat keyLeft
und right
hat keyRight
anstelle von key
, müssen Sie left_on
angeben. und right_on
als Argumente anstelle von on
:
left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)
left2
keyLeft value
0 A 1.764052
1 B 0.400157
2 C 0.978738
3 D 2.240893
right2
keyRight value
0 B 1.867558
1 D -0.977278
2 E 0.950088
3 F -0.151357
left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
keyLeft value_x keyRight value_y
0 B 0.400157 B 1.867558
1 D 2.240893 D -0.977278
Beim Zusammenführen von keyLeft
von left
und keyRight
von right
, wenn Sie nur eines der keyLeft
oder keyRight
(aber nicht beide) möchten In der Ausgabe können Sie als ersten Schritt den Index festlegen.
left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')
value_x keyRight value_y
0 0.400157 B 1.867558
1 2.240893 D -0.977278
Vergleichen Sie dies mit der Ausgabe des Befehls kurz vor (d. H. Der Ausgabe von left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
), und Sie werden feststellen, dass keyLeft
fehlt. Sie können herausfinden, welche Spalte basierend auf dem Index des Frames als Schlüssel beibehalten werden soll. Dies kann beispielsweise dann von Bedeutung sein, wenn eine OUTER JOIN-Operation ausgeführt wird.
DataFrames
zusammenführen Zum Beispiel betrachten
right3 = right.assign(newcol=np.arange(len(right)))
right3
key value newcol
0 B 1.867558 0
1 D -0.977278 1
2 E 0.950088 2
3 F -0.151357 3
Wenn Sie nur "new_val" (ohne eine der anderen Spalten) zusammenführen müssen, können Sie vor dem Zusammenführen in der Regel nur einige Spalten auswählen:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
Wenn Sie einen LEFT OUTER JOIN durchführen, würde eine performantere Lösung map
beinhalten:
# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Wie bereits erwähnt, ist dies ähnlich, aber schneller als
left.merge(right3[['key', 'newcol']], on='key', how='left')
key value newcol
0 A 1.764052 NaN
1 B 0.400157 0.0
2 C 0.978738 NaN
3 D 2.240893 1.0
Um an mehr als einer Spalte teilzunehmen, geben Sie eine Liste für on
an (oder left_on
und right_on
entsprechend).
left.merge(right, on=['key1', 'key2'] ...)
Oder, falls die Namen unterschiedlich sind,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
merge*
Operationen und Funktionen Neben merge
werden DataFrame.update
und DataFrame.combine_first
in bestimmten Fällen auch verwendet, um einen DataFrame mit einem anderen zu aktualisieren.
pd.merge_ordered
ist eine nützliche Funktion für bestellte JOINs.
pd.merge_asof
(read: merge_asOf) ist nützlich für ungefähre Joins.
In diesem Abschnitt werden nur die Grundlagen behandelt. Er soll nur Ihren Appetit anregen. Weitere Beispiele und Fälle finden Sie in der Dokumentation zu merge
, join
und concat
sowie in den Links zu den Funktionsspezifikationen.
merge
s)Setup
np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'
left
value
idxkey
A -0.602923
B -0.402655
C 0.302329
D -0.524349
right
value
idxkey
B 0.543843
D 0.013135
E -0.326498
F 1.385076
In der Regel sieht eine Zusammenführung im Index folgendermaßen aus:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Wenn Ihr Index benannt ist, können Benutzer der Version 0.23 den Ebenennamen auch mit on
(oder left_on
und right_on
nach Bedarf) angeben.
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Es ist möglich (und ziemlich einfach), den Index eines und die Spalte eines anderen zu verwenden, um eine Zusammenführung durchzuführen. Zum Beispiel,
left.merge(right, left_on='key1', right_index=True)
Oder umgekehrt (right_on=...
und left_index=True
).
right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2
colkey value
0 B 0.543843
1 D 0.013135
2 E -0.326498
3 F 1.385076
left.merge(right2, left_index=True, right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
In diesem speziellen Fall wird der Index für left
benannt, sodass Sie den Indexnamen auch mit left_on
verwenden können.
left.merge(right2, left_on='idxkey', right_on='colkey')
value_x colkey value_y
0 -0.402655 B 0.543843
1 -0.524349 D 0.013135
DataFrame.join
Neben diesen gibt es eine weitere prägnante Option. Sie können DataFrame.join
verwenden, der standardmäßig Verknüpfungen im Index erstellt. DataFrame.join
führt standardmäßig einen LEFT OUTER JOIN durch, daher ist hier how='inner'
erforderlich.
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Beachten Sie, dass ich die Argumente lsuffix
und rsuffix
angeben musste, da join
andernfalls einen Fehler verursachen würde:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
Da die Spaltennamen gleich sind. Dies wäre kein Problem, wenn sie anders benannt wären.
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
Als Alternative für indexbasierte Joins können Sie auch pd.concat
verwenden:
pd.concat([left, right], axis=1, sort=False, join='inner')
value value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Lassen Sie join='inner'
weg, wenn Sie einen FULL OUTER JOIN benötigen (Standardeinstellung):
pd.concat([left, right], axis=1, sort=False)
value value
A -0.602923 NaN
B -0.402655 0.543843
C 0.302329 NaN
D -0.524349 0.013135
E NaN -0.326498
F NaN 1.385076
Weitere Informationen finden Sie unter dieser kanonische Beitrag zu pd.concat
von @piRSquared .
merge
mehrere DataFramesIn vielen Fällen tritt die Situation auf, wenn mehrere DataFrames zusammengeführt werden sollen. Naiv kann dies durch Verketten von merge
Aufrufen erfolgen:
df1.merge(df2, ...).merge(df3, ...)
Dies gerät jedoch bei vielen DataFrames schnell außer Kontrolle. Darüber hinaus kann es erforderlich sein, für eine unbekannte Anzahl von DataFrames eine Verallgemeinerung vorzunehmen.
Hier stelle ich pd.concat
für Mehrfachverknüpfungen mit eindeutigen Schlüsseln und DataFrame.join
für Mehrfachverknüpfungen mit nicht eindeutigen Schlüsseln vor. Zunächst das Setup.
# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C]
# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')
dfs2 = [A2, B2, C2]
Wenn Ihre Schlüssel (hier kann es sich entweder um eine Spalte oder einen Index handeln) eindeutig sind, können Sie pd.concat
verwenden. Beachten Sie, dass pd.concat
DataFrames im Index verbindet .
# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')
valueA valueB valueC
key
D 2.240893 -0.977278 1.0
Lassen Sie join='inner'
weg, um eine vollständige äußere Verknüpfung zu erhalten. Beachten Sie, dass Sie keine LEFT- oder RIGHT-OUTER-Joins angeben können (wenn Sie diese benötigen, verwenden Sie join
, wie unten beschrieben).
concat
ist schnell, hat aber seine Mängel. Duplikate können nicht verarbeitet werden.
A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})
pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)
In dieser Situation können wir join
verwenden, da es nicht eindeutige Schlüssel verarbeiten kann (beachten Sie, dass join
DataFrames in ihrem Index verbindet; es ruft merge
unter der Haube auf und führt einen LEFT OUTER JOIN aus Falls nicht anders angegeben).
# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
[df.set_index('key') for df in (B, C)], how='inner').reset_index()
key valueA valueB valueC
0 D 2.240893 -0.977278 1.0
# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')
valueA valueB valueC
key
D 1.454274 -0.977278 1.0
D 0.761038 -0.977278 1.0