... unire due DataFrame di Pandas

Il problema

In questo articolo voglio vedere come unire 2 DataFrame di Pandas. Il problema è inquadrato nella figura sotto, dati due DataFrame che contengono dati diversi voglio combinare questi due in modo da avere un unico DataFrame alla fine del processo.

Pandas mette a disposizione la funzione merge() per fare questa unione.

L’unione verrà fatta sulla base di una chiave (id nell’esempio), gli elementi dei due DataFrame con lo stesso id vengono combinati in una unica riga nel nuovo DataFrame.

Se un id non è comune ai due DataFrame… ci sono diverse possibilità. Nell’esempio sotto ho fatto un inner merge in cui ho usato solo gli id comuni ai due DataFrame di partenza. Vedremo più avanti le altre possibilità.

title

Unione orizzontale

Generiamo 2 DataFrame

In [1]:
import pandas as pd

primo_df = pd.DataFrame(columns=("id_paziente", "nome", "cognome"), data=[[1, 'Pippo', 'Baudo'], 
                                                                          [2, 'Nino', 'Frassica'], 
                                                                          [3, 'Renzo', 'Arbore']])
secondo_df = pd.DataFrame(columns=("id_paziente", "altezza", "peso"), data=[[2, 173, 97], 
                                                                            [1, 184, 98]])
In [2]:
print(primo_df.head())
print('\n')
print(secondo_df.head())
   id_paziente   nome   cognome
0            1  Pippo     Baudo
1            2   Nino  Frassica
2            3  Renzo    Arbore


   id_paziente  altezza  peso
0            2      173    97
1            1      184    98

Voglio unire ‘orizzontalemente’ i due DataFrame creati, per fare questo posso usare il metodo pd.merge() e indicando quale chiave usare per il merge usando il parametro on=’nome-colonna’.

Per esempio se uso come chiave id_paziente, il sistema cercherà gli elementi con lo stesso id_paziente nei due DataFrame e farà il merge orizzontale degli elementi con lo stesso id_paziente.

Usando il merge() senza nessuna specificazione del parametro ‘how’

In [3]:
pd.merge(left=primo_df, right=secondo_df, on='id_paziente')
Out[3]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184 98
1 2 Nino Frassica 173 97

Equivale al default how = ‘inner’. In questo caso verranno usate come chiavi del DataFrame risultate le chiavi comuni tra i due (o l’intersezione delle chiavi se preferite).

Come si vede il terzo elemento del primo DateFrame viene eliminato nel DataFrame risultante

In [4]:
pd.merge(left=primo_df, right=secondo_df, how='inner', on='id_paziente')
Out[4]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184 98
1 2 Nino Frassica 173 97

Usando how=’outer’ invece viene fatta una unione delle chiavi. Se un DataFrame non ha alcune delle chiavi gli elementi mancnto vengono riempiti con NaN

In [5]:
pd.merge(left=primo_df, right=secondo_df, how='outer', on='id_paziente')
Out[5]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184.0 98.0
1 2 Nino Frassica 173.0 97.0
2 3 Renzo Arbore NaN NaN

Specificando il parametro how=’left’ il merge utilizza tutti gli elementi della chiave (keys) del DataFrame specificato col parametro left=’nome-dataframe’, la chiave è sempre specificata con il parametro on=’nome-colonna’.

Se l’altro DataFrame manca di alcuni (o tutti) gli elementi della chiave gli elementi mancanti verranno riempiti con NaN.

In [6]:
pd.merge(left=primo_df, right=secondo_df, how='left', on='id_paziente')
Out[6]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184.0 98.0
1 2 Nino Frassica 173.0 97.0
2 3 Renzo Arbore NaN NaN

Analogamente se uso come parametro how=’right’ verranno usate le chiavi del DataFrame specificato in right=’nome-datafame’.

Come si vede poichè in questo caso il DataFrame di destra ha meno chiavi del DataFrame di sinistra, le chiavi in eccesso del DataFrame di sinistra verranno eliminate.

In [7]:
pd.merge(left=primo_df, right=secondo_df, how='right', on='id_paziente')
Out[7]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184 98
1 2 Nino Frassica 173 97

Un altro modo di usare il metodo merge() è quello di usare direttamente il metodo dello specifico DataFrame, per esempio

In [8]:
primo_df.merge(secondo_df, how='outer', on='id_paziente')
Out[8]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184.0 98.0
1 2 Nino Frassica 173.0 97.0
2 3 Renzo Arbore NaN NaN

Un caso particolare è quando i due DataFrame hanno chiavi di nomi diversi, per esempio

In [9]:
primo_df = pd.DataFrame(columns=("id_paziente", "nome", "cognome"), data=[[1, 'Pippo', 'Baudo'], 
                                                                          [2, 'Nino', 'Frassica'], 
                                                                          [3, 'Renzo', 'Arbore']])

secondo_df = pd.DataFrame(columns=("dati_paziente", "altezza", "peso"), data=[[2, 173, 97],
                                                                              [1, 184, 98]])

in questo caso posso indicare separatamente quale chiave usare per il DataFrame di sinistra e quale chiave per il DataFrame di destra

In [10]:
pd.merge(left=primo_df, right=secondo_df, left_on="id_paziente", right_on='dati_paziente', how='outer')
Out[10]:
  id_paziente nome cognome dati_paziente altezza peso
0 1 Pippo Baudo 1.0 184.0 98.0
1 2 Nino Frassica 2.0 173.0 97.0
2 3 Renzo Arbore NaN NaN NaN

In questo caso dal momento che, uno dei due tra id_paziente e dati_paziente è ridondante posso decidere di eliminare una delle due colonne. Usando il metodo drop() con parametri il nome della colonna da eliminare e l’asse verticale (axis=1) per indicare si tratta di una colonna

In [11]:
pd.merge(left=primo_df, right=secondo_df, left_on="id_paziente", right_on='dati_paziente', how='outer').drop('dati_paziente', axis=1)
Out[11]:
  id_paziente nome cognome altezza peso
0 1 Pippo Baudo 184.0 98.0
1 2 Nino Frassica 173.0 97.0
2 3 Renzo Arbore NaN NaN

Unione verticale

Voglio fare il merge orizzontale ei due DataFrame contenenti lo stesso tipo di dati (aka le stesse colonne)

In [12]:
primo_df = pd.DataFrame(columns=("id_paziente", "nome", "cognome"), data=[[3, 'Pippo', 'Baudo'], 
                                                                          [1, 'Nino', 'Frassica'], 
                                                                          [2, 'Renzo', 'Arbore']])
secondo_df = pd.DataFrame(columns=("id_paziente", "nome", "cognome"), data=[[4, 'Gigi', 'D''alessio'],
                                                                            [5, 'Massimo', 'Ranieri']])

in questo caso è sufficiente non indicare nessuna chiave e specificare che si tratta di un outer merge

In [13]:
pd.merge(primo_df, secondo_df, how='outer')
Out[13]:
  id_paziente nome cognome
0 3 Pippo Baudo
1 1 Nino Frassica
2 2 Renzo Arbore
3 4 Gigi Dalessio
4 5 Massimo Ranieri

oppure

In [14]:
primo_df.merge(secondo_df, how='outer')
Out[14]:
  id_paziente nome cognome
0 3 Pippo Baudo
1 1 Nino Frassica
2 2 Renzo Arbore
3 4 Gigi Dalessio
4 5 Massimo Ranieri

Conclusione

Ho affrontato un argomento che agli inesperti, come me, da sempre dei grattacapi: il merge di due DataFrame di Pandas.
Abbiamo visto come fare un merge orizzontale e un merge verticale. Abbiamo visto le diverse opzioni per specificare come vogliamo fare il merge.

Leave a Reply

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>