Analisi dei dati con Pandas e confronto con SQL

confronto tra pandas e sql

In questo articolo descriviamo le principali istruzioni per l’analisi dei dati della libreria Pandas di Python e le confrontiamo con la sintassi SQL equivalente. I metodi di Python saranno applicati ai Dataframe, una struttura dati molto simile alle tabelle dei Database relazionali, che organizza i dati in colonne tipizzate e righe ordinate.

Import di pandas e operazioni preliminari

Per prima cosa occorre importare la libreria pandas tramite l’istruzione

import pandas as pd

A questo punto possiamo creare un DataFrame a partire dai dati dal file Clienti.csv salvato sul mio repository di Github. Non c’è bisogno che lo scarichi, pandas è in grado di acquisire anche file csv salvati sul web! 

f = "https://raw.githubusercontent.com/iantomasinicola/Esercizi/main/Clienti.csv"
clienti = pd.read_csv(filepath_or_buffer = f,
                      sep = ";", 
                      header = 0,
                      usecols = ["NumeroCliente","Nome","Cognome",
                                 "DataNascita","Regione"],
                      parse_dates = ["DataNascita"])

Selezionare i dati di un DataFrame con Pandas

Per visualizzare il contenuto delle colonne Nome e Cognome del DataFrame clienti scriveremo

clienti[["Nome", "Cognome"]]

equivalente alla query SQL

SELECT Nome, 
       Cognome
FROM   Clienti;

Per evitare la visualizzazione di un numero eccessivo di dati, le istruzioni della libreria Pandas mostrano di default soltanto alcune delle colonne e delle righe selezionate.  Per modificare questo comportamento possiamo lanciare le istruzioni

pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)

Se vogliamo visualizzare tutte le colonne basterà eseguire la riga di codice contenente soltanto il nome del DataFrame.

Filtrare i dati di un DataFrame con Pandas

Vediamo il codice per estrarre tutte le informazioni dei clienti della regione Lazio:

clienti.query("Regione == 'Lazio'")

che è equivalente al codice SQL

SELECT * 
FROM   Clienti 
WHERE  Regione = 'Lazio';

Nelle versioni meno aggiornate di Pandas dovevo ricorrere ad una sintassi un po’ più complessa:

clienti[clienti["Regione"] == "Lazio"]

Vediamo ora come scrivere filtri più complessi, ad esempio per estrarre il NumeroCliente e il Nome dei clienti della regione Lazio che si chiamano Giovanni:

clienti.query(" Regione == 'Lazio' and Nome == 'Giovanni' "  )[["NumeroCliente","Nome"]] 

L’istruzione precedente è equivalente alla query SQL

SELECT NumeroCliente, 
       Nome 
FROM   Clienti 
WHERE  Regione = 'Lazio'
   AND Nome = 'Giovanni';

Vediamo infine come scrivere un filtro equivalente all’IN di SQL:

clienti.query( "Regione in ['Piemonte', 'Lazio'] ")[["NumeroCliente", "Nome", "Regione"]] 

è equivalente a

SELECT NumeroCliente,
       Nome,
       Regione
FROM   Clienti 
WHERE  Regione IN ('Piemonte', 'Lazio');

ed estrae i valori delle colonne NumeroCliente, Nome e Regione dei clienti residenti in Piemonte e Lazio.

Anche su pandas dobbiamo fare particolare attenzione ai null:

clienti.query("Regione.isna()" )
clienti.query("Regione.notna()" )

sono equivalenti ai filtri SQL regione IS NULL e regione IS NOT NULL. Ricordiamo infine questa importante differenza tra i due linguaggi nel caso in cui scriviamo un filtro con l’operatore != (diverso da). L’istruzione

clienti[(clienti["Regione"] != "Lazio"]

riporterà anche le righe dove la Regione è null, ciò non accade invece con il codice SQL

SELECT * 
FROM   Clienti 
WHERE  Regione <> 'Lazio';

Puoi ripassare e approfondire questi concetti con la prossima video-lezione

Metodo group by e agg per aggregare i dati di un DataFrame

Vediamo ora l’equivalente della clausola Group By su pandas. Per prima cosa importiamo un nuovo file

f2 = "https://raw.githubusercontent.com/iantomasinicola/Esercizi/main/Fatture.csv"
fatture = pd.read_csv(filepath_or_buffer = f2
                      sep = ";", 
                      header = None,
                      names = ["NumeroFattura","Tipologia","Importo",
                               "Iva","IdCliente","ResidenzaCliente",
                               "DataFattura","NumeroFornitore"],
                      parse_dates = ["DataFattura"], 
                      decimal = ",")

Vediamo una sintassi che richiede almeno la versione 1.1.5 di Pandas. Per calcolare il numero di Fatture per ogni fornitore importiamo la libreria numpy e usiamo i metodi groupby e agg:

import numpy as np
fatture.groupby(by = "NumeroFornitore", 
                as_index = False,
                dropna = False) \
       .agg(conteggio = ("NumeroFattura", 
                         np.size) )

equivalente al codice SQL

SELECT   NumeroFornitore, 
         COUNT(*)
FROM     Fatture
GROUP BY NumeroFornitore;

Se dobbiamo scrivere un’aggregazione su più colonne, ad esempio su NumeroFornitore e IdCliente, che calcoli anche somme e medie, useremo:

  • una lista nel parametro by di groupby
  • i metodi sum, mean e size di numpy nell’agg.
fatture.groupby(by = ["NumeroFornitore", "IdCliente"], 
                as_index = False, 
                dropna = False) \
       .agg(somma_importo = ("Importo", 
                             np.sum),
            media_importo = ("Importo", 
                             np.mean),
            conteggio = ("NumeroFattura",
                         np.size))

L’argomento dropna=False è necessario per evitare che vengano eliminate le righe contenenti dei null nelle colonne raggruppate. Puoi trovare un mio approfondimento sul metodo groupby in questo articolo.

corso di analisi dei dati
Se vuoi diventare un esperto (qualunque sia il tuo livello di partenza) ti invito a visitare l’anteprima gratuita della piattaforma –> La Scuola dei Dati <–

Metodo merge per combinare i dati di più DataFrame

Siamo arrivati finalmente alla classica operazioni di join, che su pandas corrisponde al metodo merge. Ad esempio una inner join tra le tabelle Fatture e Clienti come questa

SELECT *
FROM   Fatture AS F
INNER JOIN Clienti AS C
 ON F.IdCliente = C.NumeroCliente;

è equivalente a una merge tra DataFrame scritta in questo modo

pd.merge(fatture, 
         clienti, 
         how = "inner",
         left_on = "IdCliente", 
         right_on = "NumeroCliente")

Se i due DataFrame hanno delle colonne con lo stesso nome, saranno disambiguate nell’output finale dai suffissi “_x” e “_y”. Tali suffissi sono configurabili tramite il parametro suffixes, scrivendo ad esempio suffixes = (“_fatture”, “_clienti”). Le varie tipologie di join SQL sono eseguibili su pandas valorizzando correttamente l’argomento how. I termini inner, left, right e cross coincidono, invece la full join va tradotta con il valore outer. In questo articolo trovi un approfondimento sul metodo merge di Pandas.

Continua a imparare

Torna in alto
Torna su