Introduzione a Pandas: un primo sguardo al merge e join dei DataFrame

by theArchitect
SHARE
Introduzione a Pandas: un primo sguardo al merge e join dei DataFrame
© Guida-HTML5.it

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, inner per tenere solo i record validi in entrambe le tabelle.
  • Evita colonne con lo stesso nome non necessarie: se ci sono conflitti, usa i parametri suffixes o rinomina le colonne prima del merge.
  • Controlla i valori mancanti dopo l’unione: i NaN possono indicare record mancanti o errori nei dati di origine.
  • Usa indicator=True quando stai debuggando: è un ottimo strumento per capire da dove arrivano le righe.
  • Preferisci nomi di colonna chiari: chiavi come cliente_id e ordine_id rendono 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

SHARE