Dieser Beitrag soll den Lesern eine Einführung in das Zusammenführen von SQLas mit Pandas geben, wie man es benutzt und wann man es nicht benutzt.
Im Folgenden wird Folgendes beschrieben:
Was dieser Beitrag nicht durchmachen wird:
- Leistungsbezogene Diskussionen und Timings (vorerst). Meist bemerkenswerte Erwähnungen besserer Alternativen, wo immer dies angebracht ist.
- Behandeln von Suffixen, Entfernen zusätzlicher Spalten, Umbenennen von Ausgaben und anderer spezifischer Anwendungsfälle. Es gibt andere (sprich: bessere) Beiträge, die sich damit befassen, also finde es heraus!
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 alle DataFrames hier kopiert und repliziert werden, damit Sie mit ihnen spielen können. In diesem Beitrag
erfahren Sie auch, wie Sie DataFrames aus Ihrer Zwischenablage lesen.
Zuletzt wurden alle visuellen Darstellungen von JOIN-Vorgängen mithilfe von Google Drawings von Hand gezeichnet. Inspiration von hier .
Genug geredet, zeig mir einfach, wie man es benutzt merge
!
Installieren
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 hat die Schlüsselspalte (vorerst) den gleichen Namen.
Ein INNER JOIN wird vertreten durch
Hinweis
: Zusammen mit den bevorstehenden Zahlen folgen alle dieser Konvention:
- Blau zeigt Zeilen an, die im Zusammenführungsergebnis vorhanden sind
- rot zeigt Zeilen an, die vom Ergebnis ausgeschlossen sind (dh entfernt wurden)
- Grün zeigt fehlende Werte an, die im Ergebnis durch NaNs ersetzt werden
Um einen INNER JOIN auszuführen, rufen Sie merge
den linken DataFrame auf und geben Sie den rechten DataFrame und den Join-Schlüssel (zumindest) als Argumente an.
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
Dies gibt nur Zeilen aus left
und right
die einen gemeinsamen Schlüssel (in diesem Beispiel „B“ und „D).
Ein LEFT OUTER JOIN oder LEFT JOIN wird durch dargestellt
Dies kann durch Angabe erfolgen how='left'
.
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 angeben how='left'
, werden nur Schlüssel von left
verwendet, und fehlende Daten von werden right
durch NaN ersetzt.
Und in ähnlicher Weise für einen RIGHT OUTER JOIN oder RIGHT JOIN, der ...
... angeben how='right'
:
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 von right
verwendet und fehlende Daten von left
durch NaN ersetzt.
Zum Schluss für den FULL OUTER JOIN , gegeben von
angeben how='outer'
.
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:
Andere VERBINDUNGEN - LINKS-AUSSCHLIESSEN, RECHTS-AUSSCHLIESSLICH und VOLLSTÄNDIG / ANTI-VERBINDUNGEN
Wenn Sie LINKS -AUSSCHLIESSLICHE VERBINDUNGEN und RECHTS-AUSSCHLUSS-VERBINDUNGEN in zwei Schritten benötigen .
Für LEFT-Excluding JOIN, dargestellt als
Führen Sie zunächst einen LEFT OUTER JOIN durch und filtern Sie dann (ausgenommen!) Zeilen, die left
nur von 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-AUSSCHLIESSLICHEN 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
Wenn Sie eine Zusammenführung durchführen müssen, bei der nur die Schlüssel von links oder rechts, aber nicht beide beibehalten werden (IOW, Durchfü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
Unterschiedliche Namen für Schlüsselspalten
Wenn die Schlüsselspalten unterschiedlich benannt sind, z. B. left
has keyLeft
und right
has keyRight
anstelle von, key
müssen Sie left_on
und right_on
als Argumente angeben, anstatt 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
Vermeiden doppelter Schlüsselspalten in der Ausgabe
Wenn Sie beim Zusammenführen keyLeft
von left
und keyRight
von right
nur eines keyLeft
oder keyRight
(aber nicht beide) in der Ausgabe verwenden möchten , können Sie zunächst den Index als vorläufigen Schritt 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 (die Ausgabe von left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')
), Sie werden feststellen, dass sie keyLeft
fehlt. Sie können anhand des Frame-Index als Schlüssel herausfinden, welche Spalte beibehalten werden soll. Dies kann von Bedeutung sein, wenn beispielsweise eine OUTER JOIN-Operation ausgeführt wird.
Zusammenführen nur einer einzelnen Spalte aus einer der DataFrames
Betrachten Sie zum Beispiel
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 normalerweise nur Spalten unterteilen:
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 leistungsfähigere Lösung Folgendes beinhalten map
:
# 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
Zusammenführen mehrerer Spalten
Geben Sie eine Liste für on
(oder left_on
und) an right_on
, um mehr als einer Spalte beizutreten .
left.merge(right, on=['key1', 'key2'] ...)
Oder falls die Namen unterschiedlich sind,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
Andere nützliche merge*
Operationen und Funktionen
Dieser Abschnitt behandelt nur die Grundlagen und soll nur Ihren Appetit anregen. Weitere Beispiele und Fälle finden Sie in der Dokumentation merge
, join
undconcat
sowie die Links zu den Funktionsdaten.
Indexbasiertes * -JOIN (+ Indexspalte merge
s)
Installieren
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 des 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
Unterstützung für Indexnamen
Wenn Ihr Index benannt ist, können Benutzer von Version 0.23 auch den Ebenennamen für 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
Zusammenführen auf Index einer, Spalte (n) einer anderen
Es ist möglich (und recht 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 wie folgt verwenden können left_on
:
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
Daneben gibt es noch eine weitere prägnante Option. Sie können DataFrame.join
die Standardeinstellungen für Verknüpfungen im Index verwenden. DataFrame.join
führt standardmäßig einen LEFT OUTER JOIN durch, how='inner'
ist hier also 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 angeben musste, rsuffix
da join
sonst ein Fehler auftreten 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 Folgendes verwenden pd.concat
:
pd.concat([left, right], axis=1, sort=False, join='inner')
value value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
join='inner'
Lassen Sie es aus, 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 in diesem kanonischen Beitrag pd.concat
von @piRSquared .
Verallgemeinern: merge
Mehrere DataFrames
Oft tritt die Situation auf, wenn mehrere DataFrames zusammengeführt werden sollen. Naiv kann dies durch Verketten von merge
Anrufen erfolgen:
df1.merge(df2, ...).merge(df3, ...)
Dies gerät jedoch für viele DataFrames schnell außer Kontrolle. Darüber hinaus kann es erforderlich sein, eine unbekannte Anzahl von DataFrames zu verallgemeinern.
Hier stelle ich pd.concat
für Mehrweg-Verknüpfungen mit eindeutigen Schlüsseln und DataFrame.join
für Mehrweg-Verknü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]
Mehrfachzusammenführung auf eindeutigen Schlüsseln (oder Index)
Wenn Ihre Schlüssel (hier kann der Schlüssel entweder eine Spalte oder ein Index sein) eindeutig sind, können Sie sie verwenden pd.concat
. Beachten Sie, dass pd.concat
DataFrames im Index verknüpft werden .
# 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
join='inner'
Lassen Sie für eine VOLLSTÄNDIGE AUSSENVERBINDUNG aus. Beachten Sie, dass Sie keine Verknüpfungen für LINKS oder RECHTS AUSSEN angeben können (falls erforderlich, verwenden Sie join
die unten beschriebenen Verknüpfungen ).
Mehrweg-Zusammenführung von Schlüsseln mit Duplikaten
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 verwenden, join
da es nicht eindeutige Schlüssel verarbeiten kann (beachten Sie, dass join
DataFrames in ihrem Index verknüpft werden; es wird merge
unter der Haube aufgerufen und führt eine LEFT OUTER JOIN durch, sofern 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
concat
undmerge
mit einem Richtungsparameterhorizontal
odervertical
.axis=1
undaxis=0
ist?merge
undconcat
und Achse und was auch immer. Wie @eliu zeigt, ist es jedoch alles das gleiche Konzept der Zusammenführung mit "links" und "rechts" und "horizontal" oder "vertikal". Ich persönlich muss jedes Mal in die Dokumentation schauen, wenn ich mich daran erinnern muss, welche "Achse"0
und welche ist1
.