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 merge
il 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 left
e right
che 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'
, left
vengono utilizzate solo le chiavi di e i dati mancanti da right
vengono 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 right
vengono utilizzate le chiavi da e i dati mancanti da left
vengono 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 left
solo 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, left
ha keyLeft
e right
ha keyRight
invece di key
— allora dovrai specificare left_on
e right_on
come 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 keyLeft
da left
e keyRight
da right
, se si desidera solo uno keyLeft
o 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 keyLeft
manca. 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_on
e 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
, join
econcat
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_on
e 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 left
viene 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.join
impostazioni predefinite per i join sull'indice. DataFrame.join
fa 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 lsuffix
e rsuffix
poiché join
altrimenti 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: merge
ing DataFrames multipli
Spesso, la situazione si presenta quando più DataFrame devono essere uniti insieme. Ingenuamente, questo può essere fatto concatenando le merge
chiamate:
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.concat
per i join a più vie su chiavi univoche e DataFrame.join
per 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.concat
unisce 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 join
poiché può gestire chiavi non univoche (nota che join
unisce DataFrames sul loro indice; chiama merge
sotto 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