Unione di panda 101


365
  • Come eseguire un join ( LEFT| RIGHT| FULL) ( INNER| OUTER) con i panda?
  • Come faccio ad aggiungere NaN per le righe mancanti dopo l'unione?
  • Come posso eliminare NaNs dopo la fusione?
  • Posso unire l'indice?
  • Incrocio con i panda?
  • Come unire più DataFrame?
  • merge? join? concat? update? Oms? Che cosa? Perché?!

... e altro ancora. Ho visto queste domande ricorrenti fare domande su varie sfaccettature della funzionalità di unione dei panda. La maggior parte delle informazioni relative all'unione e ai suoi vari casi d'uso oggi è frammentata in dozzine di post mal formulati e non ricercabili. L'obiettivo qui è quello di raccogliere alcuni dei punti più importanti per i posteri.

Questo QnA è pensato per essere la prossima puntata di una serie di utili guide per l'utente sui comuni idiomi dei panda (vedi questo post sul pivot e questo post sulla concatenazione , che toccherò più avanti).

Nota che questo post non è destinato a sostituire la documentazione , quindi leggi anche quello! Alcuni esempi sono presi da lì.

Risposte:


520

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:

  • Nozioni di base - tipi di join (SINISTRA, DESTRA, ESTERNO, INTERNO)

    • fusione con nomi di colonne differenti
    • evitando duplicati colonna chiave di unione nell'output
  • Fusione con indice in condizioni diverse
    • utilizzando efficacemente il tuo indice denominato
    • unisci chiave come indice di una e colonna di un'altra
  • Unione multipla su colonne e indici (unici e non unici)
  • Notevoli alternative a mergeejoin

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:

inserisci qui la descrizione dell'immagine

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

49

Una vista visiva supplementare di pd.concat([df0, df1], kwargs). Nota che, il significato di kwarg axis=0o axis=1non è così intuitivo come df.mean()odf.apply(func)


su pd.concat ([df0, df1])


9
Questo è un bel diagramma. Posso chiederti come l'hai prodotta?
cs95,

6
"insert ==> drawing ... ==> new" incorporato di google doc (a partire da 2019-maggio). Ma, per essere chiari: l'unica ragione per cui ho usato google doc per questa immagine è perché i miei appunti sono memorizzati in google doc e vorrei un'immagine che possa essere modificata rapidamente all'interno di google doc stesso. In realtà ora lo hai menzionato, lo strumento di disegno del documento di Google è abbastanza pulito.
eliu

Wow, è fantastico. Proveniente dal mondo SQL, il join "verticale" non è un join nella mia testa, poiché la struttura della tabella è sempre fissa. Ora anche pensare che i panda dovrebbero consolidarsi concate mergecon un parametro direction che sia horizontalo vertical.
Ufo

2
@Ufos Non è esattamente quello axis=1che axis=0è?
cs95,

2
sì, ci stiamo ora mergee concate l'asse e quant'altro. Tuttavia, come mostra @eliu, è tutto lo stesso concetto di unione con "sinistra" e "destra" e "orizzontale" o "verticale". Personalmente, devo esaminare la documentazione ogni volta che devo ricordare quale "asse" è 0e quale è 1.
Ufo
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.