Creare tabelle pivot con pandas

Molto spesso, dopo aver analizzato dei dati tramite l’utilizzo della libreria pandas, ci capita di doverli condividere con altri. E se volessimo formattare i nostri dati in una tabella pivot per renderli più fruibili? Dobbiamo davvero esportare i dati su un file Excel, aprirlo a creare manualmente una tabella pivot? Ovviamente no. Possiamo costruirne una con pandas!

Partiamo dal dataframe

Immaginiamo di avere a nostra disposizione il dataframe di cui abbiamo già parlato in questo articolo che indica il valore di alcuni account di (potenziali) clienti con le relative informazioni.

Immagine 1

Immagine 1

Adesso immaginiamo di voler costruire una tabella pivot che renda visibile il valore degli account segmentati per mercato.

#importiamo le librerie pandas e numpy
import pandas as pd
import numpy as np

#creiamo la tabella pivot
pd.pivot_table(df,index = 'Mercato')

Diamo un’occhiata al risultato:

Immagine 2

Immagine 2

Come possiamo vedere, abbiamo una tabella pivot. Abbiamo impostato la colonna “Mercato” come indice della tabella così come volevamo. Tuttavia, dei valori delle colonne “N° account” e “Valore account”, essendo numerici, è stata fatta la media. Questo è semplicemente non esatto.

Specificare le operazioni da eseguire

Nel caso della tabella pivot raffigurata in alto, sarebbe corretto avere la somma del valore degli account nell’ultima colonna e il numero di account nella prima.

Per fare questo, occorre specificare le operazioni da eseguire per ogni colonna.

pd.pivot_table(df,index = 'Mercato',
               aggfunc = {'N° account':len,'Valore account':np.sum})

Risultato:

Immagine 3

Immagine 3

Come possiamo vedere abbiamo ottenuto quel che volevamo. Per la colonna “N° account” abbiamo contato i valori (len), mentre per quella “Valore account” li abbiamo sommati (np.sum).

Eseguire più operazioni per la stessa colonna

Supponiamo però di voler rappresentare sia la somma che la media del valore degli account per mercato direttamente nella nostra tabella pivot. In questo caso, non ci resta che attribuire due operazioni alla colonna “Valore account”:

pd.pivot_table(df,index = 'Mercato',
    aggfunc = {'N° account':len, 'Valore account':[np.sum,np.mean]})

Risultato:

Immagine 4

Immagine 4

La prima colonna è rimasta invariata. La seconda invece è divisa in due parti: la prima che indica il valore medio degli account di un mercato (mean) e la seconda che specifica il loro valore totale (sum).

Aggiungere più indici

Molto spesso, quando realizziamo una classica tabella pivot con Excel, siamo soliti impostare due o più indici, in modo da avere uno spaccato accurato ed ordinato dei nostri dati. Cerchiamo di farlo anche con pandas: proveremo a costruire la tabella pivot raffigurata nell’Immagine 4, aggiungendovi una segmentazione aggiuntiva basata sullo stato dei nostri account.

pd.pivot_table(df, index = ['Status','Mercato'],
        aggfunc = {'N° account':len, 'Valore account':[np.mean,np.sum]})

Risultato:

Immagine 5

Immagine 5

Quindi per aggiungere un’ulteriore livello di segmentazione alla nostra tabella pivot, non ci resta che aggiungere la colonna desiderata all’indice. Il risultato finale rispecchierà l’ordine nel quale queste colonne vengono menzionate nel codice. Ad esempio se invertissimo “Status” e “Mercato” nella maniera seguente:

pd.pivot_table(df, index = [Mercato','Status'],
        aggfunc = {'N° account':len, 'Valore account':[np.mean,np.sum]})

otterremo la tabella pivot seguente:

Immagine 6

Immagine 6

Ricapitolando, aggiungendo colonne all’argomento index del comando pd.pivot_table possiamo ottenere ulteriori livelli di segmentazione dei dati nell’ordine desiderato.

Selezionare i valori da includere

Come abbiamo visto negli esempi riportati fin qui, le tabelle pivot generate con pandas includono automaticamente tutte le colonne con valori numerici in quella che sarebbe la sezione “valori” di una comune tabella pivot costruita con Excel. Questo è il comportamento di default.

Tuttavia, è possibile selezionare le colonne specifiche che si desidera includere nella tabella pivot. Per farlo, abbiamo bisogno di un altro argomento del comando pd.pivot_table, sarebbe a dire values.

Costruiamo una tabella pivot che ci dica soltanto la somma e la media del valore degli account, segmentando questi ultimi per mercato e Paese.

pd.pivot_table(df, index = ['Mercato','Paese'],
               values = 'Valore account',
               aggfunc=[np.sum,np.mean])

Risultato:

Immagine 7

Immagine 7

In questo caso, abbiamo specificato di voler raffigurare soltanto la colonna “Valore account” tramite l’argomento values. Poi, come già visto in un esempio precedente, abbiamo ottenuto sia la somma che la media dei valori di questa colonna con l’argomento aggfunc.

Aggiungere il totale

Alla tabella pivot dell’immagine 7 manca qualcosa: il totale! Contrariamente a quanto accade in Excel dove la riga con il totale appare di default, in pandas abbiamo bisogno di specificare di volerla. Questo si fa con l’argomento margins.

pd.pivot_table(df, index = ['Mercato','Paese'],
               values = 'Valore account',
               aggfunc=[np.sum,np.mean],
               margins = True, margins_name = 'Totale')

Risultato:

Immagine 8

Immagine 8

Ricapitolando, il valore di default dell’argomento margins è sempre “False” a meno che non si specifichi il contrario. Nell’esempio abbiamo anche deciso di specificare il nome da dare alla riga del totale tramite l’argomento margins_name. Questo non è obbligatorio dato che pandas normalmente attribuirà a questa riga il nome “All”.

Aggiungere le colonne

Rispetto al loro corrispettivo in Excel, le tabelle pivot raffigurate sin qui non hanno una raggruppamento dei dati per colonne. Ciò è possibile utilizzando l’argomento columns.

pd.pivot_table(df, index = ['Mercato','Paese'],
               values = 'Valore account',
               columns = 'Status',
               aggfunc=[np.sum,np.mean],
               margins = True, margins_name = 'Totale')

Risultato:

Immagine 9

Immagine 9

Come possiamo vedere, abbiamo una segmentazione al livello delle righe per marcato e Paese ed una al livello delle colonne a seconda dello status di ogni account. Non avendo apportato eccessive modifiche alla tabella pivot usata negli esempi precedenti, abbiamo conservato sia la somma che la media del valore degli account.

Migliorare la leggibilità: eliminare NaN

La tabella pivot raffigurata nell’immagine 9 offre una rappresentazione accurata dei dati ma pecca un po’ in quanto a leggibilità. Possiamo provare a migliorare la sua fruibilità sostituendo i valori nulli (NaN) con qualcosa di più leggibile. Questo è possibile utilizzando l’argomento fill_value.

pd.pivot_table(df, index = ['Mercato','Paese'],
               values = 'Valore account',
               columns = 'Status',
               aggfunc = [np.sum,np.mean],
               fill_value = 0,
               margins = True, margins_name = 'Totale')

Risultato:

Immagine 10

Immagine 10

Perfetto! Con il comando fill_value abbiamo “riempito” i valori nulli con un valore a nostra scelta, in questo caso il numero zero.

Migliorare la leggibilità: arrotondare i numeri decimali

Volendo continuare a migliorare la fruibilità della nostra tabella pivot, non possiamo far altro che notare che le colonne della media del valore degli account sono alquanto confuse, sopratutto quella che indica il totale e gli account chiusi.

Infatti, in questi casi, i numeri decimali riportati nella tabella hanno ben 6 cifre dopo la virgola!

Possiamo decidere di limitare questo fenomeno utilizzando il metodo round() che non è un’esclusiva delle tabelle pivot con pandas, ma può essere utilizzato in qualsiasi script in Python. Diamo un’occhiata al nostro codice:

pd.pivot_table(df, index = ['Mercato','Paese'],
               values = 'Valore account',
               columns = 'Status',
               aggfunc = [np.sum,np.mean],
               fill_value = 0,
               margins = True, margins_name = 'Totale').round(2)

Risultato:

Immagine 11

Immagine 11

Abbiamo ottenuto una tabella pivot in cui i numeri decimali hanno al massimo due cifre dopo la virgola. Come abbiamo potuto constatare, il metodo round() ci permette di specificare quanti numeri dopo la virgola desideriamo. Qualora non scrivessimo nulla, il metodo convertirà tutti i numeri decimali in numeri interi, arrotondandoli.

Filtrare una tabella pivot

Una funzione molto importante ed apprezzata delle tabelle pivot è la possibilità di applicare dei filtri aggiuntivi. Questa eventualità non ci è preclusa in pandas ed è possibile con il metodo query(). Questa non è l’unica possibilità che abbiamo per filtrare una tabella pivot o un qualsiasi dataframe con pandas, ma per ragioni di praticità è l’unica che osserveremo in questo articolo. Diamo un’occhiata al codice:

pd.pivot_table(df, index = ['Mercato','Paese'],
        values = 'Valore account',
        columns = 'Status',
        aggfunc = [np.sum,np.mean],
        fill_value = 0,
        margins = True,
        margins_name = 'Totale').round(2).query('Mercato == ["Altro"]')

Risultato:

Immagine 12

Immagine 12

In questo caso abbiamo filtrato la tabella pivot raffigurata nell’immagine 11 affinché contenesse solo i valori corrispondenti al mercato segmentato come “Altro”.

Conclusione

Il comando pd.pivot_table ci permette di manipolare i dati con pandas in maniera molto simile a ciò che faremmo in un banalissimo foglio di calcolo. Personalmente mi avvalgo sovente di pandas per costruire delle tabelle pivot soprattutto al fine di velocizzare le operazioni di reportistica aziendale.