Vai al contenuto principale

Indici gerarchici, groupby e pandas

In questo tutorial imparerai i multi-index per i DataFrame di pandas e come nascono naturalmente dalle operazioni di groupby su dataset reali.
Aggiornato 29 set 2026  · 9 min leggi

Scopri con l'IA

ChatGPTClaudePerplexity

In un post precedente hai visto come l’operazione di groupby emerga in modo naturale attraverso il principio split-apply-combine. Hai esaminato un dataset con le valutazioni degli utenti Netflix e raggruppato le righe per anno di uscita del film per generare la figura seguente:

pandas groupby

Questo risultato è stato ottenuto raggruppando per una singola colonna. Ho accennato, di sfuggita, che potresti voler raggruppare per più colonne: in tal caso, il DataFrame pandas risultante avrà un multi-index o indice gerarchico. In questo post imparerai cosa sono gli indici gerarchici e vedrai come si generano quando raggruppi in base a più caratteristiche dei tuoi dati. Puoi approfondire tutti questi concetti e pratiche nel nostro corso Manipulating DataFrames with pandas.

Partiamo: cosa sono gli indici gerarchici?

hierarchical index pandas

Indici gerarchici e DataFrame di pandas

Cos’è l’indice di un DataFrame?

Prima di introdurre gli indici gerarchici, voglio che tu ricordi cos’è l’indice di un DataFrame pandas. L’indice di un DataFrame è un insieme composto da un’etichetta per ogni riga. Vediamo un esempio. Importerò innanzitutto un dataset sintetico con l’attività su DataCamp di Ellie, una studentessa ipotetica. Le colonne sono una data, un linguaggio di programmazione e il numero di esercizi che Ellie ha completato quel giorno in quel linguaggio. Carica i dati:

# Import pandas
import pandas as pd

# Load in data
df = pd.read_csv('data/user_ex_python.csv')
df
 

Esegui e modifica il codice da questo tutorial online

Esegui codice
  date language ex_complete
0 2017-01-01 python 6
1 2017-01-02 python 5
2 2017-01-03 python 10

Puoi vedere l’indice sul lato sinistro del DataFrame, ed è composto da interi. Si tratta di un RangeIndex:

# Check out index
df.index
RangeIndex(start=0, stop=3, step=1)

Possiamo usare questo indice per estrarre una o più righe di df:

# Slice and dice data
df.loc[:1]
  date language ex_complete
0 2017-01-01 python 6
1 2017-01-02 python 5

Tuttavia, questo indice non è molto informativo. Se vuoi etichettare le righe del tuo DataFrame, è meglio farlo in modo significativo, quando possibile. Si può fare con questo dataset? Un buon modo di affrontare la cosa è cercare un identificatore univoco e significativo per ogni riga. Dai un’occhiata alle colonne e verifica se qualcuna soddisfa questi criteri. Nota che la colonna date contiene date univoche, quindi ha senso etichettare ogni riga con la data. Cioè, puoi rendere la colonna date l’indice del DataFrame usando il metodo .set_index() (n.b. inplace=True significa che stai modificando effettivamente il DataFrame df in place):

# Set new index
df.set_index(pd.DatetimeIndex(df['date']), inplace=True)
df
  date language ex_complete
date      
2017-01-01 2017-01-01 python 6
2017-01-02 2017-01-02 python 5
2017-01-03 2017-01-03 python 10

Questo assegna a df un DateTimeIndex:

# Check out new index
df.index
DatetimeIndex(['2017-01-01', '2017-01-02', '2017-01-03'], dtype='datetime64[ns]', name='date', freq=None)

Ora puoi estrarre righe usando il DateTimeIndex che hai creato:

# Slice and dice data w/ new index
df.loc['2017-01-02']
date           2017-01-02
language           python
ex_complete             5
Name: 2017-01-02 00:00:00, dtype: object

Nota anche che l’attributo .columns restituisce un indice contenente i nomi delle colonne di df:

# Check out columns
df.columns
Index(['date', 'language', 'ex_complete'], dtype='object')

Questo può creare un po’ di confusione, perché indica che df.columns è di tipo Index. Questo non significa che le colonne siano l’indice del DataFrame. L’indice di df è sempre dato da df.index. Dai un’occhiata al nostro tutorial sui DataFrame di pandas per saperne di più sugli indici. Ora è il momento di incontrare gli indici gerarchici.

Il multi-index di un DataFrame pandas

E se avessimo più linguaggi nel nostro dataset, come succede su DataCamp? Guarda qui:

# Import and check out data
df = pd.read_csv('data/user_ex.csv')
df
  date language ex_complete
0 2017-01-01 python 6
1 2017-01-02 python 5
2 2017-01-03 python 10
3 2017-01-01 r 8
4 2017-01-02 r 8
5 2017-01-03 r 8

Ora ogni data corrisponde a più righe, una per ciascun linguaggio. Ad esempio, la data ‘2017-01-02’ appare nelle righe 1 e 4, per i linguaggi Python e R rispettivamente. Quindi la data non specifica più univocamente la riga. Tuttavia, ‘date’ e ‘language’ insieme la specificano in modo univoco. Per questo motivo usiamo entrambe come indice:

# Set index
df.set_index(['date', 'language'], inplace=True)
df
    ex_complete
date language  
2017-01-01 python 6
2017-01-02 python 5
2017-01-03 python 10
2017-01-01 r 8
2017-01-02 r 8
2017-01-03 r 8

Hai appena creato un multi-index, o indice gerarchico (abituati a entrambi i termini, li troverai usati in modo intercambiabile), e puoi verificarlo controllando l’indice come segue:

# Check out multi-index
df.index
MultiIndex(levels=[['2017-01-01', '2017-01-02', '2017-01-03'], ['python', 'r']],
           labels=[[0, 1, 2, 0, 1, 2], [0, 0, 0, 1, 1, 1]],
           names=['date', 'language'])

Quanto sopra ti dice che il tuo DataFrame df ora ha un MultiIndex con due livelli, il primo dato dalla data, il secondo dal linguaggio. Ricorda che prima potevi eseguire slicing del DataFrame usando l’indice e l’accessor .loc: df.loc['2017-01-02']. Per poter fare slicing con un multi-index, devi prima ordinarlo:

# Sort index
df.sort_index(inplace=True)
df
    ex_complete
date language  
2017-01-01 python 6
r 8
2017-01-02 python 5
r 8
2017-01-03 python 10
r 8

Ora puoi estrarre il numero di esercizi in R completati il 2017-01-02 passando una tupla all’accessor .loc:

# Slice & dice your DataFrame
df.loc[('2017-01-02', 'r')]

ex_complete 8 Name: (2017-01-02, r), dtype: int64

Quando e perché usare i multi-index

I multi-index sono uno strumento potente per l’analisi e l’organizzazione dei dati in pandas. Permettono di creare indici gerarchici, utili per raggruppare e aggregare i dati su più dimensioni. Sono particolarmente utili con dataset complessi che presentano più livelli di categorizzazione, come dati finanziari o serie temporali.

Creando un multi-index, puoi raggruppare i dati simultaneamente per più variabili, rivelando insight che potrebbero non emergere con un raggruppamento a singolo livello. Ad esempio, i multi-index permettono di raggruppare per tempo e località, consentendo di analizzare i trend in specifiche regioni nel tempo.

Inoltre, i multi-index consentono selezioni e sottoinsiemi efficienti, poiché l’indice offre un modo comodo per accedere a subset specifici dei dati. In sintesi, i multi-index sono fondamentali per organizzare, raggruppare e analizzare dataset complessi in pandas e sono essenziali per chiunque lavori con dati gerarchici.

Ora che conosci gli indici gerarchici (o multi-indici), vediamo come emergono lavorando con gli oggetti groupby.

Indici gerarchici, oggetti groupby e Split-Apply-Combine

In un post precedente abbiamo esplorato gli oggetti groupby e i principi analitici di split-apply-combine usando dati di Netflix. Facciamo un rapido ripasso con un dataset diverso, il dataset tips incluso nel pacchetto seaborn. ‘Tips’ contiene caratteristiche come tip, total_bill, il giorno della settimana e l’orario. Per prima cosa carica ed esplora i dati:

# Import and check out data
import seaborn as sns
tips = sns.load_dataset("tips")
tips.head()
  total_bill tip sex smoker day time size
0 16.99 1.01 Female No Sun Dinner 2
1 10.34 1.66 Male No Sun Dinner 3
2 21.01 3.50 Male No Sun Dinner 3
3 23.68 3.31 Male No Sun Dinner 2
4 24.59 3.61 Female No Sun Dinner 4

Nota che l’indice di tips è un RangeIndex:

# Check out index
tips.index
RangeIndex(start=0, stop=244, step=1)

È sempre utile fare un po’ di EDA visiva prima di tuffarsi nei calcoli e la funzione pairplot di seaborn ti permette di avere una panoramica di tutte le variabili numeriche:

# Import pyplot, figures inline, set style, plot pairplot
import matplotlib.pyplot as plt
%matplotlib inline
sns.set()
sns.pairplot(tips, hue='day');

different charts

Se vuoi vedere come differisce la mancia media tra ‘smokers’ e ‘non-smokers’, puoi dividere il DataFrame originale per ‘smoker’ (usando groupby), applicare la funzione ‘mean’ e combinare in un nuovo DataFrame:

# Get mean of smoker/non-smoker groups
df = tips.groupby('smoker').mean()
df
  total_bill tip size
smoker      
Yes 20.756344 3.008710 2.408602
No 19.188278 2.991854 2.668874

L’indice risultante del DataFrame df è la colonna/feature ‘smoker’ del DataFrame ‘tips’ originale:

# Check out new index
df.index
CategoricalIndex(['Yes', 'No'], categories=['Yes', 'No'], ordered=False, name='smoker', dtype='category')

Se vuoi, puoi resettare l’indice così che ‘smoker’ torni a essere una colonna del DataFrame:

# Reset the index
df.reset_index()
  smoker total_bill tip size
0 Yes 20.756344 3.008710 2.408602
1 No 19.188278 2.991854 2.668874

Ora è il momento di vedere come gli indici gerarchici derivino da split-apply-combine e dalle operazioni di groupby.

Raggruppamenti multipli e indici gerarchici

Qui sopra hai raggruppato il dataset tips in base alla feature ‘smoker’. A volte avrai bisogno di raggruppare un dataset in base a due feature. Ad esempio, è naturale raggruppare tips in fumatori/non fumatori & cena/pranzo. Per farlo, passa come lista i nomi delle colonne per cui vuoi raggruppare:

# Group by two columns
df = tips.groupby(['smoker','time']).mean()
df
    total_bill tip size
smoker time      
Yes Lunch 17.399130 2.834348 2.217391
Dinner 21.859429 3.066000 2.471429
No Lunch 17.050889 2.673778 2.511111
Dinner 20.095660 3.126887 2.735849

Guardando sopra, potresti notare che sia ‘smoker’ che ‘time’ sono indici di df. È così e ha senso: se raggruppare per ‘smoker’ rende l’indice la colonna ‘smoker’ originale, raggruppare per due colonne ti darà due indici. Controlla l’indice per confermare che sia gerarchico:

# Check out index
df.index
MultiIndex(levels=[['Yes', 'No'], ['Lunch', 'Dinner']],
           labels=[[0, 0, 1, 1], [0, 1, 0, 1]],
           names=['smoker', 'time'])

Ed è così. Ora puoi fare un sacco di cose utili, come ottenere le frequenze in ciascun raggruppamento:

# Group by two features
tips.groupby(['smoker','time']).size()
smoker  time  
Yes     Lunch      23
        Dinner     70
No      Lunch      45
        Dinner    106
dtype: int64

Puoi anche scambiare i livelli dell’indice gerarchico, così che ‘time’ venga prima di ‘smoker’ nell’indice:

# Swap levels of multi-index
df.swaplevel()
    total_bill tip size
time smoker      
Lunch Yes 17.399130 2.834348 2.217391
Dinner Yes 21.859429 3.066000 2.471429
Lunch No 17.050889 2.673778 2.511111
Dinner No 20.095660 3.126887 2.735849

Potresti poi voler rimuovere una di queste feature dall’indice gerarchico e creare colonne diverse rispetto a quella feature. Puoi farlo con il metodo unstack:

# Unstack your multi-index
df.unstack()
  total_bill tip size
time Lunch Dinner Lunch Dinner Lunch Dinner
smoker            
Yes 17.399130 21.859429 2.834348 3.066000 2.217391 2.471429
No 17.050889 20.095660 2.673778 3.126887 2.511111 2.735849

Puoi fare unstack sulla feature esterna dell’indice usando l’argomento ‘level’:

# Unsstack the outer index
df.unstack(level=0)
  total_bill tip size
smoker Yes No Yes No Yes No
time            
Lunch 17.399130 17.050889 2.834348 2.673778 2.217391 2.511111
Dinner 21.859429 20.095660 3.066000 3.126887 2.471429 2.735849

Il risultato di unstack ha un indice non gerarchico, come ti aspetteresti:

# Check out index
df.unstack().index
CategoricalIndex(['Yes', 'No'], categories=['Yes', 'No'], ordered=False, name='smoker', dtype='category')

Di conseguenza, ora puoi eseguire ogni tipo di analisi rispetto a questi raggruppamenti. Ti incoraggio a farlo.

Indici gerarchici nell’uso quotidiano

In questo post hai conosciuto gli indici gerarchici (o multi-indici) e visto come nascano come conseguenza naturale del desiderio di avere un indice del DataFrame che etichetti le righe in modo univoco e significativo. Hai anche visto come emergano quando devi raggruppare i dati per più colonne, applicando il principio split-apply-combine. Spero che ti divertirai a usare gli indici gerarchici nel tuo lavoro.

Questo post è stato generato da un Jupyter Notebook; puoi trovarlo in questo repository. Se hai pensieri, commenti e/o riflessioni, contattami su Twitter: @hugobowne.

Dai un’occhiata anche agli altri pratici tutorial su pandas di DataCamp, tra cui:

Argomenti
Python
Data Science

Approfondisci Python e pandas

Corso

Join con pandas per chi usa i fogli di calcolo

4 ore
4.5K
Scopri come unire in modo efficace ed efficiente set di dati in formato tabellare usando la libreria Python Pandas.
Vedi i dettagliRight Arrow
Inizia Il Corso
Mostra altroRight Arrow
Correlato

blog

Tokenizzazione nel NLP: come funziona, sfide e casi d'uso

Guida al preprocessing NLP nel machine learning. Copriamo spaCy, i transformer di Hugging Face e come funziona la tokenizzazione in casi d'uso reali.
Abid Ali Awan's photo

Abid Ali Awan

10 min

blog

Che cos'è Snowflake? Guida per principianti alla piattaforma dati cloud

Esplora le basi di Snowflake, la piattaforma dati cloud. Scopri la sua architettura, le sue funzionalità e come integrarla nelle tue pipeline di dati.
Tim Lu's photo

Tim Lu

12 min

blog

I 15 migliori server MCP remoti che ogni AI builder dovrebbe conoscere nel 2026

Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Abid Ali Awan's photo

Abid Ali Awan

15 min

Mostra AltroMostra Altro