Questo post ha lo scopo di dare ai lettori un primer sulla fusione basata su SQL con i panda, su come usarlo e quando non usarlo.
In particolare, ecco cosa passerà questo post:
Cosa non passerà questo post:
- Discussioni e tempistiche relative alle prestazioni (per ora). Menzioni principalmente degne di nota di alternative migliori, ove opportuno.
- Gestire i suffissi, rimuovere colonne aggiuntive, rinominare gli output e altri casi d'uso specifici. Ci sono altri post (leggi: migliori) che si occupano di questo, quindi scoprilo!
Nota
La maggior parte degli esempi imposta automaticamente le operazioni INNER JOIN mentre mostra varie funzioni, se non diversamente specificato.
Inoltre, tutti i DataFrame qui possono essere copiati e replicati in modo da poter giocare con loro. Inoltre, vedi questo post
su come leggere DataFrames dagli appunti.
Infine, tutta la rappresentazione visiva delle operazioni JOIN è stata disegnata a mano utilizzando i Disegni di Google. Ispirazione da qui .
Basta parlare, fammi vedere come usare merge!
Impostare
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
Per semplicità, la colonna chiave ha lo stesso nome (per ora).
Un INNER JOIN è rappresentato da

Nota
Questo, insieme alle figure imminenti seguono tutti questa convenzione:
- il blu indica le righe presenti nel risultato dell'unione
- il rosso indica le righe escluse dal risultato (ovvero rimosse)
- il verde indica i valori mancanti che vengono sostituiti con NaN nel risultato
Per eseguire un INNER JOIN, chiama mergeil DataFrame di sinistra, specificando il DataFrame di destra e la chiave di join (almeno) come argomenti.
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
Ciò restituisce solo righe da lefte rightche condividono una chiave comune (in questo esempio, "B" e "D).
Un JOIN ESTERNO SINISTRA o JOIN SINISTRA è rappresentato da

Questo può essere eseguito specificando 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
Nota attentamente il posizionamento di NaN qui. Se si specifica how='left', leftvengono utilizzate solo le chiavi di e i dati mancanti da rightvengono sostituiti da NaN.
E allo stesso modo, per un JOU ESTERNO DESTRA , o JOIN DESTRA che è ...

... specificare 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
Qui rightvengono utilizzate le chiavi da e i dati mancanti da leftvengono sostituiti da NaN.
Infine, per il FULL OUTER JOIN , fornito da

specificare 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
Questo utilizza le chiavi di entrambi i frame e vengono inseriti NaN per le righe mancanti in entrambi.
La documentazione riassume bene queste varie fusioni:

Altri JOIN - LEFT-Excluding, RIGHT-Excluding e FULL-Excluding / ANTI JOINs
Se hai bisogno di JOIN esclusi a sinistra e JOIN esclusi a destra in due passaggi.
Per JOIN escluso SINISTRO, rappresentato come

Inizia eseguendo un LEFT OUTER JOIN e quindi filtrando (escludendo!) Le righe provenienti leftsolo da ,
(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
Dove,
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
Allo stesso modo, per un JOIN ad esclusione di DESTRA,

(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
Infine, se ti viene richiesto di eseguire un'unione che conserva solo le chiavi da sinistra o destra, ma non entrambe (IOW, eseguendo un ANTI-JOIN ),

Puoi farlo in modo simile—
(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
Nomi diversi per colonne chiave
Se le colonne chiave sono denominate in modo diverso, ad esempio, leftha keyLefte rightha keyRightinvece di key— allora dovrai specificare left_one right_oncome argomenti invece di 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
Evitare la colonna chiave duplicata nell'output
Quando si uniscono keyLeftda lefte keyRightda right, se si desidera solo uno keyLefto keyRight(ma non entrambi) nell'output, è possibile iniziare impostando l'indice come passaggio preliminare.
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
Contrastalo con l'output del comando appena prima (questo è, l'output di left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), noterai che keyLeftmanca. Puoi capire quale colonna mantenere in base all'indice del frame impostato come chiave. Questo può essere importante quando, ad esempio, si esegue un'operazione OUTER JOIN.
Unione di una sola colonna da una delle DataFrames
Ad esempio, considera
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
Se ti viene richiesto di unire solo "new_val" (senza nessuna delle altre colonne), in genere puoi semplicemente sottoinsieme di colonne prima di unire:
left.merge(right3[['key', 'newcol']], on='key')
key value newcol
0 B 0.400157 0
1 D 2.240893 1
Se stai effettuando un JOIN ESTERNO SINISTRO, una soluzione più performante implicherebbe 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
Come accennato, questo è simile, ma più veloce di
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
Unione su più colonne
Per partecipare su più di una colonna, specificare un elenco per on(o left_one right_on, a seconda dei casi).
left.merge(right, on=['key1', 'key2'] ...)
Oppure, nel caso in cui i nomi siano diversi,
left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])
Altre merge*operazioni e funzioni utili
Questa sezione tratta solo le basi, ed è progettata per stimolare solo l'appetito. Per ulteriori esempi e casi, consultare la documentazione su merge, joineconcat così come i collegamenti alle specifiche funzioni.
Basato su indice * -JOIN (+ colonne-indice merge)
Impostare
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 genere, un'unione su indice sarebbe simile a questa:
left.merge(right, left_index=True, right_index=True)
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Supporto per i nomi degli indici
Se l'indice è chiamato, quindi v0.23 gli utenti possono anche specificare il nome del livello di on(o left_one right_on, se necessario).
left.merge(right, on='idxkey')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Unione sull'indice di una, colonna (e) di un'altra
È possibile (e abbastanza semplice) utilizzare l'indice di uno e la colonna di un altro per eseguire un'unione. Per esempio,
left.merge(right, left_on='key1', right_index=True)
O viceversa ( right_on=...e 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 questo caso speciale, l'indice per leftviene chiamato, quindi puoi anche usare il nome indice con left_on, in questo modo:
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
Oltre a questi, c'è un'altra opzione concisa. È possibile utilizzare le DataFrame.joinimpostazioni predefinite per i join sull'indice. DataFrame.joinfa un JOIN ESTERNO SINISTRA di default, quindi how='inner'è necessario qui.
left.join(right, how='inner', lsuffix='_x', rsuffix='_y')
value_x value_y
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
Si noti che dovevo specificare gli argomenti lsuffixe rsuffixpoiché joinaltrimenti verrebbero fuori errore:
left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
Poiché i nomi delle colonne sono gli stessi. Questo non sarebbe un problema se fossero nominati diversamente.
left.rename(columns={'value':'leftvalue'}).join(right, how='inner')
leftvalue value
idxkey
B -0.402655 0.543843
D -0.524349 0.013135
pd.concat
Infine, in alternativa ai join basati su indice, è possibile utilizzare 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
Ometti join='inner'se hai bisogno di UN ENTRA COMPLETO ESTERNO (impostazione predefinita):
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
Per ulteriori informazioni, vedere questo post canonico su pd.concat@piRSquared .
Generalizzazione: mergeing DataFrames multipli
Spesso, la situazione si presenta quando più DataFrame devono essere uniti insieme. Ingenuamente, questo può essere fatto concatenando le mergechiamate:
df1.merge(df2, ...).merge(df3, ...)
Tuttavia, ciò sfugge rapidamente a molti DataFrame. Inoltre, potrebbe essere necessario generalizzare per un numero sconosciuto di DataFrames.
Qui presento pd.concatper i join a più vie su chiavi univoche e DataFrame.joinper i join a più vie su chiavi non univoche . Innanzitutto, l'installazione.
# 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]
Unione a più vie su chiavi univoche (o indice)
Se le tue chiavi (qui, la chiave può essere una colonna o un indice) sono uniche, puoi usare pd.concat. Si noti che pd.concatunisce DataFrames sull'indice .
# 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
Ometti join='inner'per UN'UNIONE COMPLETA ESTERNA. Notare che non è possibile specificare i join LEFT o RIGHT OUTER (se necessario, utilizzare join, descritto di seguito).
Unione a più vie su chiavi con duplicati
concatè veloce, ma ha i suoi difetti. Non può gestire i duplicati.
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 questa situazione, possiamo usarlo joinpoiché può gestire chiavi non univoche (nota che joinunisce DataFrames sul loro indice; chiama mergesotto il cofano ed esegue un JOIN ESTERNO SINISTRO se non diversamente specificato).
# 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