Introduzione
Pandas è una delle librerie più usate in Python per lavorare con dati tabellari. Se stai iniziando a usarla, probabilmente hai già visto come creare un DataFrame, selezionare colonne, filtrare righe o calcolare statistiche di base. Un passo molto utile, però, è imparare a unire più tabelle in modo corretto.
Questo tutorial introduce un sotto-argomento pratico e fondamentale: il merge e il join tra DataFrame. Nella realtà, i dati arrivano quasi sempre da fonti diverse: un file con gli ordini, uno con i clienti, uno con i prodotti. Per analizzarli bene, bisogna spesso combinarli in un’unica struttura coerente.
Vedremo come funzionano le operazioni più importanti per collegare dati relazionati, con un esempio realistico e codice commentato. L’obiettivo è capire quando usare merge, come scegliere la chiave di unione e come evitare errori comuni.
Codice completo
import pandas as pd
# Tabella clienti
clienti = pd.DataFrame({
"cliente_id": [101, 102, 103, 104],
"nome": ["Anna", "Luca", "Sara", "Marco"],
"citta": ["Milano", "Roma", "Torino", "Napoli"]
})
# Tabella ordini
ordini = pd.DataFrame({
"ordine_id": [1, 2, 3, 4, 5],
"cliente_id": [101, 102, 101, 105, 103],
"prodotto": ["Mouse", "Tastiera", "Monitor", "Webcam", "Cuffie"],
"importo": [25.0, 45.0, 180.0, 60.0, 35.0]
})
# Tabella pagamenti
pagamenti = pd.DataFrame({
"ordine_id": [1, 2, 3, 5],
"stato_pagamento": ["Pagato", "Pagato", "In attesa", "Pagato"]
})
print("=== CLIENTI ===")
print(clienti)
print("n=== ORDINI ===")
print(ordini)
print("n=== PAGAMENTI ===")
print(pagamenti)
# 1) Merge tra ordini e clienti usando la colonna cliente_id
ordini_clienti = pd.merge(
ordini,
clienti,
on="cliente_id",
how="left"
)
print("n=== ORDINI + CLIENTI (LEFT JOIN) ===")
print(ordini_clienti)
# 2) Merge tra ordini_clienti e pagamenti usando ordine_id
report_completo = pd.merge(
ordini_clienti,
pagamenti,
on="ordine_id",
how="left"
)
print("n=== REPORT COMPLETO ===")
print(report_completo)
# 3) Individuare gli ordini senza cliente corrispondente
ordini_senza_cliente = report_completo[report_completo["nome"].isna()]
print("n=== ORDINI SENZA CLIENTE CORRISPONDENTE ===")
print(ordini_senza_cliente)
# 4) Trovare i clienti che non hanno effettuato ordini
clienti_con_ordini = pd.merge(
clienti,
ordini,
on="cliente_id",
how="left",
indicator=True
)
clienti_senza_ordini = clienti_con_ordini[clienti_con_ordini["_merge"] == "left_only"]
print("n=== CLIENTI SENZA ORDINI ===")
print(clienti_senza_ordini[["cliente_id", "nome", "citta"]])
# 5) Esempio di join tramite indice
clienti_indice = clienti.set_index("cliente_id")
ordini_indice = ordini.set_index("cliente_id")
join_indice = ordini_indice.join(clienti_indice, how="left", rsuffix="_cliente")
print("n=== JOIN TRAMITE INDICE ===")
print(join_indice) Spiegazione
Il cuore di questo tutorial è l’operazione di unione tra DataFrame. In Pandas, il metodo più usato è merge(), che funziona in modo molto simile ai join dei database relazionali.
1. Perché unire i DataFrame?
Immagina di avere dati separati in più tabelle:
- una tabella con i dati anagrafici dei clienti;
- una tabella con gli ordini;
- una tabella con lo stato dei pagamenti.
Da sole, queste tabelle raccontano solo una parte della storia. Unendole, puoi rispondere a domande più interessanti, per esempio:
- quali clienti hanno acquistato di più;
- quali ordini non risultano ancora pagati;
- quali clienti non hanno mai effettuato un ordine.
2. Il metodo merge()
La funzione pd.merge() unisce due DataFrame usando una colonna comune, detta chiave. Nel nostro esempio, la colonna cliente_id collega la tabella ordini con la tabella clienti.
La sintassi base è:
pd.merge(df_sinistro, df_destro, on="chiave", how="tipo_join") Il parametro how definisce il tipo di unione:
- left: mantiene tutte le righe del DataFrame di sinistra;
- right: mantiene tutte le righe del DataFrame di destra;
- inner: mantiene solo le righe presenti in entrambi;
- outer: mantiene tutte le righe di entrambi, inserendo valori mancanti dove serve.
3. Unione tra ordini e clienti
Nel codice, il primo merge crea ordini_clienti. Usiamo how="left" perché vogliamo conservare tutti gli ordini, anche quelli che non trovano un cliente corrispondente. Questo è utile per individuare dati incoerenti.
Nel nostro esempio, l’ordine con cliente_id = 105 non trova corrispondenza nella tabella clienti. Il risultato avrà quindi valori NaN nelle colonne del cliente.
4. Secondo merge: aggiungere i pagamenti
Successivamente uniamo il risultato precedente con la tabella pagamenti usando ordine_id. In questo modo otteniamo un report più completo, con informazioni su cliente, prodotto, importo e stato del pagamento.
Questo tipo di pipeline è molto comune nei progetti reali: si parte da tabelle separate e si costruisce un dataset finale pronto per analisi, report o dashboard.
5. Trovare dati mancanti o incoerenti
Una delle attività più importanti quando si uniscono tabelle è controllare la qualità del dato. Nel codice usiamo:
report_completo[report_completo["nome"].isna()] per trovare gli ordini senza cliente associato. La presenza di NaN segnala che la chiave di unione non ha trovato una corrispondenza.
Usiamo anche il parametro indicator=True per capire quali clienti non hanno ordini. Pandas aggiunge una colonna speciale chiamata _merge, utile per verificare l’origine di ogni riga dopo l’unione.
6. Join tramite indice
Oltre a merge(), Pandas offre anche join(), spesso comodo quando la chiave di collegamento è già impostata come indice del DataFrame. Nel nostro esempio trasformiamo cliente_id in indice con set_index() e poi facciamo il join.
In pratica:
- merge() è più flessibile e molto usato;
- join() è utile quando lavori direttamente con gli indici.
Best practice
- Controlla sempre la qualità delle chiavi: prima di unire tabelle, verifica che i valori siano coerenti e possibilmente univoci.
- Usa il tipo di join corretto:
leftè utile per mantenere il dataset principale,innerper tenere solo i record validi in entrambe le tabelle. - Evita colonne con lo stesso nome non necessarie: se ci sono conflitti, usa i parametri
suffixeso rinomina le colonne prima del merge. - Controlla i valori mancanti dopo l’unione: i
NaNpossono indicare record mancanti o errori nei dati di origine. - Usa
indicator=Truequando stai debuggando: è un ottimo strumento per capire da dove arrivano le righe. - Preferisci nomi di colonna chiari: chiavi come
cliente_ideordine_idrendono il codice molto più leggibile.
Riepilogo
In questo tutorial hai visto come unire DataFrame in Pandas usando merge() e join(). Questo è uno dei passaggi più importanti quando lavori con dati reali, perché quasi mai le informazioni sono già raccolte in un’unica tabella.
Hai imparato che:
- merge() collega due DataFrame tramite una chiave comune;
- how decide quali righe mantenere;
- NaN aiutano a individuare dati mancanti o non corrispondenti;
- indicator=True è utile per il controllo qualità;
- join() è pratico quando lavori con gli indici.
Se vuoi usare Pandas in modo efficace, imparare a combinare tabelle è un’abilità essenziale. Ti permette di passare da dati sparsi a dataset completi, pronti per analisi, reportistica e machine learning.
Approfondisci con risorse ufficiali
- Documentazione ufficiale di Pandas - Merge, join, concatenate: https://pandas.pydata.org/docs/user_guide/merging.html
- API reference di pandas.merge: https://pandas.pydata.org/docs/reference/api/pandas.merge.html
- API reference di DataFrame.join: https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.join.html
- Guida ufficiale ai DataFrame: https://pandas.pydata.org/docs/user_guide/dsintro.html#dataframe
