Istogrammi Matplotlib in Python — Guida Completa
Impara a creare e personalizzare istogrammi in Python con Matplotlib. Copre bin, densità, sovrapposizione KDE, cumulativi, affiancati e salvataggio su file.
La funzione hist() di Matplotlib rende semplice visualizzare come un dataset è distribuito su un intervallo numerico. Questo capitolo tratta tutto, dal primo istogramma minimo alle tecniche pratiche che utilizzerai nei progetti reali: scegliere il numero giusto di bin, tracciare la densità invece dei conteggi grezzi, sovrapporre una curva KDE, confrontare distribuzioni multiple e salvare il risultato in un file.
Prima di iniziare, assicurati che Matplotlib e NumPy siano installati:
pip install matplotlib numpySe sei nuovo alla libreria, consulta prima i capitoli Introduzione a Matplotlib e Per Iniziare.
Cos'è un Istogramma?
Un istogramma divide una variabile numerica continua in intervalli equidistanti chiamati bin e disegna una barra per ciascun bin la cui altezza è uguale al numero di osservazioni che ricadono in quell'intervallo. A differenza di un grafico a barre, che confronta categorie discrete, un istogramma rivela la forma di una distribuzione — se è simmetrica, asimmetrica, bimodale o presenta valori anomali.
Usa un istogramma quando vuoi rispondere a domande come:
- Dove è concentrata la maggior parte dei dati?
- La distribuzione è approssimativamente normale, o è asimmetrica?
- Ci sono lacune o picchi multipli (dati bimodali)?
- Ci sono valori anomali lontani dalla massa dei dati?
Creare un Istogramma di Base
Passa un array o una lista monodimensionale a plt.hist() e Matplotlib sceglie automaticamente il numero di bin:
import matplotlib.pyplot as plt
import numpy as np
# Reproducible example: 1 000 values from a normal distribution
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data)
plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()plt.tight_layout() impedisce che le etichette degli assi vengano tagliate — una buona abitudine da aggiungere prima di ogni chiamata a show() o savefig().
Scegliere il Numero di Bin
Il parametro bins è il principale parametro di regolazione per un istogramma. Troppo pochi bin nascondono la struttura; troppi bin creano rumore.
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
for ax, n_bins in zip(axes, [5, 30, 100]):
ax.hist(data, bins=n_bins, color='steelblue', edgecolor='white')
ax.set_title(f'bins={n_bins}')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
plt.suptitle('Effect of Bin Count', y=1.02)
plt.tight_layout()
plt.show()Linee guida pratiche:
- 5–10 bin — utili per dataset molto piccoli (n < 50) o panoramiche rapide.
- 20–50 bin — buon valore predefinito per la maggior parte dei dataset (n = 100–10 000).
- 50–100+ bin — appropriato per dataset di grandi dimensioni (n > 10 000) dove la struttura fine è importante.
- Passa una regola come stringa invece di un numero:
bins='auto',bins='fd'(Freedman–Diaconis), obins='sturges'— Matplotlib delega anp.histogram_bin_edges()di NumPy.
Puoi anche passare una lista esplicita di bordi di bin per una spaziatura non uniforme:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.exponential(scale=2, size=1000)
# Finer bins near 0, coarser bins in the tail
edges = [0, 0.5, 1, 1.5, 2, 3, 4, 6, 8, 12]
plt.hist(data, bins=edges, color='darkorange', edgecolor='white')
plt.title('Custom Bin Edges (Exponential Data)')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()Personalizzare l'Aspetto
Colore, Trasparenza e Bordo
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=5, scale=1.5, size=800)
plt.hist(
data,
bins=30,
color='steelblue',
edgecolor='white', # thin white line between bars
linewidth=0.5,
alpha=0.85, # slight transparency
)
plt.title('Styled Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.show()alpha (0 = completamente trasparente, 1 = completamente opaco) è particolarmente utile quando si sovrappongono più istogrammi in modo che le barre non si nascondano a vicenda.
Rimuovere il Rumore Visivo
Rimuovere i bordi superiore e destro conferisce all'istogramma un aspetto più pulito:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, ax = plt.subplots(figsize=(8, 4))
ax.hist(data, bins=30, color='cornflowerblue', edgecolor='white')
ax.set_title('Clean Histogram')
ax.set_xlabel('Value')
ax.set_ylabel('Frequency')
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
plt.tight_layout()
plt.show()Istogrammi di Densità
Per impostazione predefinita hist() mostra i conteggi grezzi sull'asse y. Passa density=True per normalizzare l'asse y in modo che l'area totale di tutte le barre sia uguale a 1. Questo trasforma l'istogramma in una stima della densità di probabilità, rendendo facile confrontare dataset di dimensioni diverse.
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, density=True, color='mediumseagreen', edgecolor='white')
plt.title('Density Histogram')
plt.xlabel('Value')
plt.ylabel('Probability Density')
plt.tight_layout()
plt.show()Nota: i valori dell'asse y sono densità, non probabilità. Moltiplica una densità per la larghezza del bin per ottenere la probabilità per quel bin.
Sovrapporre una Curva KDE
Una stima di densità del kernel (KDE) è una curva regolare che approssima la distribuzione di probabilità sottostante. Sovrapporla a un istogramma di densità fornisce un quadro intuitivo della forma della distribuzione. Usa scipy.stats.gaussian_kde per calcolarla:
import matplotlib.pyplot as plt
import numpy as np
from scipy.stats import gaussian_kde
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
fig, ax = plt.subplots(figsize=(8, 4))
# Density histogram
ax.hist(data, bins=30, density=True,
color='steelblue', edgecolor='white', alpha=0.6, label='Histogram')
# KDE curve
xs = np.linspace(data.min(), data.max(), 300)
kde = gaussian_kde(data)
ax.plot(xs, kde(xs), color='navy', linewidth=2, label='KDE')
ax.set_title('Histogram with KDE Overlay')
ax.set_xlabel('Value')
ax.set_ylabel('Probability Density')
ax.legend()
plt.tight_layout()
plt.show()Installa SciPy se non è già disponibile:
pip install scipyConfrontare Distribuzioni Multiple
Per confrontare due o più distribuzioni sugli stessi assi, chiama hist() più volte e usa alpha per mantenere le barre semi-trasparenti. Imposta gli stessi bins per entrambe in modo che le larghezze delle barre siano confrontabili:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
group_a = rng.normal(loc=0, scale=1, size=500)
group_b = rng.normal(loc=2, scale=1.5, size=500)
shared_bins = np.linspace(-5, 8, 40)
plt.hist(group_a, bins=shared_bins, alpha=0.6, color='steelblue', label='Group A')
plt.hist(group_b, bins=shared_bins, alpha=0.6, color='darkorange', label='Group B')
plt.title('Overlapping Histograms')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.legend()
plt.tight_layout()
plt.show()Definire shared_bins tramite np.linspace() garantisce che entrambi gli istogrammi usino bordi di bin identici e che le loro barre si allineino visivamente.
Istogrammi Affiancati (In Pila)
Quando la sovrapposizione rende difficile leggere le distribuzioni individuali, usa plt.subplots() per posizionarle affiancate:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
group_a = rng.normal(loc=0, scale=1, size=500)
group_b = rng.normal(loc=2, scale=1.5, size=500)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 4), sharey=True)
ax1.hist(group_a, bins=30, color='steelblue', edgecolor='white')
ax1.set_title('Group A')
ax1.set_xlabel('Value')
ax1.set_ylabel('Frequency')
ax2.hist(group_b, bins=30, color='darkorange', edgecolor='white')
ax2.set_title('Group B')
ax2.set_xlabel('Value')
plt.suptitle('Side-by-Side Histograms')
plt.tight_layout()
plt.show()sharey=True blocca entrambi i subplot sulla stessa scala dell'asse y in modo che le altezze delle barre siano direttamente confrontabili. Consulta il capitolo Subplot di Matplotlib per ulteriori opzioni di layout.
Istogrammi Cumulativi
Passa cumulative=True per disegnare un istogramma in cui ogni barra rappresenta il conteggio totale delle osservazioni fino a e incluso quel bin. È utile per rispondere a domande come "quale frazione di valori è inferiore a X?":
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, cumulative=True, density=True,
color='mediumpurple', edgecolor='white')
plt.title('Cumulative Density Histogram')
plt.xlabel('Value')
plt.ylabel('Cumulative Probability')
plt.tight_layout()
plt.show()Combinato con density=True, l'istogramma cumulativo diventa un'approssimazione a funzione a gradini della CDF empirica (funzione di distribuzione cumulativa). L'asse y va da 0 a 1.
Orientamento dell'Istogramma
Passa orientation='horizontal' per disegnare barre che si estendono verso sinistra dall'asse y. È raramente la scelta predefinita, ma rispecchia il layout dei grafici di distribuzione marginale di un grafico a dispersione:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=500)
plt.hist(data, bins=20, orientation='horizontal',
color='tomato', edgecolor='white')
plt.title('Horizontal Histogram')
plt.ylabel('Value')
plt.xlabel('Frequency')
plt.tight_layout()
plt.show()Salvare un Istogramma su File
Usa plt.savefig() prima di plt.show() (o al suo posto). Specifica il formato tramite l'estensione del file:
import matplotlib.pyplot as plt
import numpy as np
rng = np.random.default_rng(42)
data = rng.normal(loc=0, scale=1, size=1000)
plt.hist(data, bins=30, color='steelblue', edgecolor='white')
plt.title('Distribution of Sample Data')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.tight_layout()
plt.savefig('histogram.png', dpi=150) # raster, good for web
plt.savefig('histogram.pdf') # vector, good for print/publication
plt.show()Formati comuni: png, pdf, svg, eps. Usa svg o pdf quando hai bisogno di un'immagine scalabile e di qualità per la stampa.
Parametri Principali di hist() — Riferimento Rapido
| Parametro | Tipo | Descrizione |
|---|---|---|
bins | int, list, o str | Numero di bin, bordi espliciti, o nome di regola ('auto', 'fd', 'sturges') |
density | bool | Normalizza in modo che l'area totale = 1 (densità di probabilità) |
cumulative | bool | Ogni barra mostra il conteggio/densità cumulativa fino a quel bin |
orientation | str | 'vertical' (predefinito) o 'horizontal' |
color | str | Colore di riempimento delle barre |
edgecolor | str | Colore del bordo delle barre; 'white' fornisce un separatore pulito |
alpha | float 0–1 | Trasparenza; impostare sotto 1 quando si sovrappongono istogrammi |
label | str | Etichetta della legenda per questo istogramma |
histtype | str | 'bar' (predefinito), 'step', 'stepfilled' |
range | (min, max) | Limita i dati a questo intervallo prima del binning |
Errori Comuni
- Semi casuali.
np.random.randn()produce valori diversi ad ogni esecuzione. Usanp.random.default_rng(seed)per esempi riproducibili. densityvsnormed. Il vecchio parametronormed=Trueè stato rimosso in Matplotlib 3.x. Usa sempredensity=True.- Confrontare istogrammi con dimensioni di campione diverse. Le barre di frequenza grezze non sono confrontabili quando le dimensioni dei gruppi differiscono — usa
density=Trueper normalizzare entrambe. - Dati interi discreti. Per i valori interi (es. lanci di dadi, valutazioni di sondaggi), imposta i bordi dei bin a mezzi interi —
bins=[0.5, 1.5, 2.5, ..., 6.5]— in modo che ogni intero rientri in esattamente un bin senza ambiguità sui bordi. plt.show()cancella la figura. Se chiamishow()e poisavefig(), ottieni un file vuoto. Chiama sempresavefig()prima dishow().
Capitoli Correlati
- Introduzione a Matplotlib — panoramica della libreria e installazione
- Matplotlib Per Iniziare — guida al primo grafico
- Grafici a Barre Matplotlib — confronto di categorie discrete
- Grafici a Dispersione Matplotlib — relazioni tra due variabili
- Grafici a Torta Matplotlib — proporzioni parte-tutto
- Etichette Matplotlib — etichette degli assi, titoli e annotazioni
- Subplot Matplotlib — grafici multipli in una sola figura
- Distribuzione dei Dati — background statistico sulle distribuzioni