Analisi dei dati con Pandas e confronto con SQL

analizzare un dataframe

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! 

clienti = pd.read_csv(filepath_or_buffer = \
"https://raw.githubusercontent.com/iantomasinicola/Esercizi/main/Clienti.csv",
                      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[clienti["Regione"] == "Lazio"]

che è equivalente al codice SQL

SELECT * 
FROM   Clienti 
WHERE  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[(clienti["Regione"] == "Lazio") \
& (clienti["Nome"] == "Giovanni")]      \
[["NumeroCliente",
  "Nome"]]

Il carattere \ serve semplicemente per andare a capo nella scrittura del codice Python. L’istruzione precedente è equivalente alla query SQL

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

Il carattere corrispondente nella sintassi di Pandas all’operatore OR è la barra verticale “|“. Ricordiamoci sempre di racchiudere le condizioni tra parentesi tonde.

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

clienti[clienti["Regione"].isin(["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[(clienti["Regione"].isna())]
clienti[(clienti["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

fatture = pd.read_csv(filepath_or_buffer = \
"https://raw.githubusercontent.com/iantomasinicola/Esercizi/main/Fatture.csv",
                      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.

 

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 customizzabili 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.

Link utili

Torna su