HOWTO · Matplotlib

Come tracciare un istogramma per una lista di dati in Matplotlib

Traccia un istogramma da una lista Python con plt.hist() di Matplotlib, quindi regolane i bin, la densità e il colore.

In questa pagina

Per tracciare un istogramma da una lista Python, passa la lista direttamente alla funzione plt.hist() di Matplotlib. La funzione raggruppa i valori in intervalli chiamati bin, conta quanti valori cadono in ciascun intervallo e disegna una barra per intervallo, così la forma del grafico mostra come sono distribuiti i valori. Come input basta una semplice lista Python; non è necessario convertirla prima in un array NumPy o in una Series pandas. Questo articolo traccia una lista di 21 numeri interi da 0 a 9, poi regola i bin, le altezze delle barre e il colore delle barre, e infine mostra cosa accade con un numero di bin non valido e con una lista vuota.

Tracciare un istogramma da una lista con plt.hist()

Senza argomenti aggiuntivi, plt.hist() divide l’intervallo dei dati in dieci bin di uguale larghezza. L’esempio cattura anche i tre valori restituiti dalla funzione e li stampa, così puoi vedere esattamente come è stata raggruppata la lista:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data)
print("counts:", counts.tolist())
print("bin_edges:", bin_edges.tolist())
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Histogram of data")
plt.show()
counts: [1.0, 1.0, 2.0, 2.0, 5.0, 3.0, 3.0, 2.0, 1.0, 1.0]
bin_edges: [0.0, 0.9, 1.8, 2.7, 3.6, 4.5, 5.4, 6.3, 7.2, 8.1, 9.0]

Istogramma dei 21 valori della lista disegnato da plt.hist() con i dieci bin predefiniti; la barra più alta copre i valori da 3,6 a 4,5 e ha un conteggio di 5.

plt.hist() restituisce tre valori. counts contiene il numero di osservazioni in ciascun bin, bin_edges fornisce i confini degli intervalli e patches contiene gli artist delle barre, nel caso tu voglia modificare in seguito lo stile di singole barre. Il numero di elementi in counts è il numero di bin, mentre bin_edges ha sempre un elemento in più perché segna entrambe le estremità di ogni intervallo. Qui l’intervallo dei dati va da 0 a 9, quindi ciascuno dei dieci bin predefiniti è largo 0,9, e la barra più alta è l’intervallo da 3,6 a 4,5, che contiene le cinque occorrenze del valore 4. Puoi omettere l’assegnazione e chiamare semplicemente plt.hist(data) se ti serve solo il grafico.

Impostare il numero di bin o i bordi dei bin

Il parametro bins controlla come vengono divisi i dati. Passare un intero come bins=20 crea quel numero di intervalli di uguale larghezza lungo l’intervallo dei dati:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data, bins=20)
print("counts:", counts.tolist())
print("number of bins:", len(counts))
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Histogram with 20 bins")
plt.show()
counts: [1.0, 0.0, 1.0, 0.0, 2.0, 0.0, 2.0, 0.0, 5.0, 0.0, 0.0, 3.0, 0.0, 3.0, 0.0, 2.0, 0.0, 1.0, 0.0, 1.0]
number of bins: 20

La stessa lista tracciata con 20 bin; molti dei bin stretti restano vuoti perché i dati contengono solo numeri interi da 0 a 9.

Venti bin sono troppi per questa piccola lista: poiché i valori sono interi, un bin su due resta vuoto e la distribuzione sembra più rumorosa di quanto sia. In generale, pochissimi bin possono nascondere la struttura dei dati, mentre molti bin stretti possono rendere frastagliato un piccolo insieme di dati, quindi scegli un numero di bin adatto alla dimensione e alla dispersione della tua lista. Invece di un intero, puoi passare una sequenza di valori di bordo come bins=[0, 2, 4, 6, 8, 10] per impostare tu stesso i confini degli intervalli; gli intervalli possono così avere larghezze diverse. Quando i conteggi coprono un intervallo ampio, l’argomento opzionale log=True imposta l’asse dei conteggi su una scala logaritmica, in modo che le barre più piccole restino visibili accanto a una barra alta. Cambia solo la scala dell’asse, non i valori di input né la suddivisione in bin.

Mostrare la densità di probabilità invece dei conteggi

Per impostazione predefinita, le altezze delle barre sono conteggi. Imposta density=True quando vuoi invece una densità di probabilità. Matplotlib scala allora le altezze in modo che l’area totale delle barre sia 1:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
counts, bin_edges, patches = plt.hist(data, bins=10, density=True)
print("densities:", [round(d, 4) for d in counts.tolist()])
area = sum(d * (bin_edges[i + 1] - bin_edges[i]) for i, d in enumerate(counts))
print("total area:", round(area, 6))
plt.xlabel("Value")
plt.ylabel("Probability density")
plt.title("Probability histogram of data")
plt.show()
densities: [0.0529, 0.0529, 0.1058, 0.1058, 0.2646, 0.1587, 0.1587, 0.1058, 0.0529, 0.0529]
total area: 1.0

Istogramma di densità di probabilità della lista disegnato con density=True; le altezze delle barre sono densità e l’area totale delle barre è 1.

Con density=True, il primo valore della tupla restituita contiene densità invece di conteggi, e l’esempio verifica la normalizzazione moltiplicando ogni densità per la larghezza del suo bin e sommando le aree, ottenendo esattamente 1. Nota che l’altezza di una singola barra è una densità, non la probabilità del suo intervallo; la probabilità di un intervallo è l’area della sua barra, cioè l’altezza moltiplicata per la larghezza. Questa distinzione conta quando i bin hanno larghezze diverse, perché una barra larga può rappresentare più probabilità di una barra stretta più alta. Ricorda di aggiornare l’etichetta dell’asse verticale quando cambi modalità, come fa l’esempio, così il grafico spiega cosa significano le altezze delle sue barre.

Cambiare il colore delle barre

Il parametro color imposta il colore di riempimento delle barre:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
plt.hist(data, bins=10, color="red")
plt.xlabel("Value")
plt.ylabel("Count")
plt.title("Red histogram of data")
plt.show()

L’istogramma della lista con barre rosse, disegnato con dieci bin e il parametro color impostato su rosso.

Funziona qualsiasi specifica di colore di Matplotlib, come un nome come "red", una stringa esadecimale come "#1f77b4" o un codice di una sola lettera. Le opzioni di visualizzazione si combinano liberamente in una sola chiamata; ad esempio, plt.hist(data, bins=20, density=True, color="red") disegna venti barre rosse con altezze di densità. Qualunque opzione tu combini, mantieni il titolo e le etichette degli assi coerenti con esse: un grafico di densità non dovrebbe conservare un’etichetta di conteggio, e un grafico con venti bin non dovrebbe dichiarare di mostrare i dieci predefiniti.

Gestire un numero di bin non valido e una lista vuota

Vale la pena conoscere due errori di input prima che ti sorprendano. Il primo è un numero di bin non positivo:

import matplotlib.pyplot as plt

data = [3, 4, 2, 3, 4, 5, 4, 7, 8, 5, 4, 6, 2, 1, 0, 9, 7, 6, 6, 5, 4]
plt.hist(data, bins=0)
Traceback (most recent call last):
  ...
ValueError: `bins` must be positive, when an integer

bins=0 (e qualsiasi intero negativo) solleva un ValueError e non viene disegnato nulla. Se il numero di bin proviene da un input dell’utente o da un calcolo, verifica che sia un intero positivo prima di tracciare, oppure passa invece una sequenza di bordi. Il secondo caso è una lista vuota, che si comporta in modo molto diverso: non è affatto un errore.

import matplotlib.pyplot as plt

counts, bin_edges, patches = plt.hist([])
print("counts:", counts.tolist())
print("bin_edges:", [round(e, 2) for e in bin_edges.tolist()])
counts: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
bin_edges: [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]

Senza dati, plt.hist() ricade sull’intervallo predefinito da 0 a 1, restituisce dieci conteggi pari a zero e disegna un insieme di assi vuoto senza sollevare eccezioni. Questo rende la lista vuota una modalità di errore silenziosa: se i tuoi dati provengono da un file, una query o un filtro, controlla che la lista non sia vuota prima di tracciare, in modo che un insieme di dati mancante non si trasformi in un grafico vuoto che sembra un risultato valido.