Misure di Posizione: Percentili, Quartili e Intervallo Interquartile
Parte (1/2)
Potrebbe interessarti:
- Misure di Posizione: Five-Number Summary, Outlier e Boxplot - (2/2)
- Misure di Variabilità: Intervallo, Varianza e Deviazione Standard - (1/2)
Il progetto Python, che comprende gli script mostrati in questo post, e quelli relativi alla creazione dei grafici Matplotlib, è disponibile assieme al corso Fondamenti di Statistica per il ML.
Le misure di posizione vengono utilizzate per individuare la posizione relativa di un valore di dati all’interno di un dataset. Esse includono z-score, percentili, decili e quartili.
Percentili
I percentili sono misure di posizione utilizzate per indicare la posizione di un valore in una distribuzione di dati, e forniscono un modo intuitivo per capire la posizione relativa di un dato all’interno della distribuzione. Dividono il dataset in $100$ gruppi uguali, e sono simboleggiati da:
$$P_1, P_2, \dots, P_{99}$$Il $k$-esimo percentile è il valore sotto il quale si trova il $k%$ delle osservazioni:

Ad esempio:
- il $25°$ percentile indica il valore sotto il quale si trova circa il $25\%$ dei dati;
- il $50°$ percentile coincide con la mediana;
- il $75°$ percentile indica il valore sotto il quale si trova circa il $75\%$ dei dati.
Supponiamo di avere i punteggi di un esame. Se uno studente è al $90°$ percentile, significa che ha ottenuto un punteggio maggiore o uguale al $90\%$ degli studenti. In altre parole, solo il 10% degli studenti ha fatto meglio:

Non esiste una singola formula universale per i percentili, ma una delle formulazioni più comuni per calcolare la posizione del percentile in un dataset ordinato è la seguente.
Posizione del Percentile
Se il dataset ha $n$ osservazioni ordinate:
$$x_{(1)} \le x_{(2)} \le \dots \le x_{(n)}$$la posizione del $k$-esimo percentile è:
$$L = \frac{k}{100}(n+1)$$dove:
- $k$ è il percentile desiderato (ad esempio $25$, $50$, $90$);
- $n$ è il numero di osservazioni;
- $L$ è la posizione del percentile nella lista ordinata.
Se $L$ è un numero intero:
$$P_k = x_{(L)}$$Se $L$ non è intero, si usa una interpolazione lineare tra i due valori vicini:
$$ P_k = x_{(\lfloor L \rfloor)} + (L - \lfloor L \rfloor) \left(x_{(\lceil L \rceil)} - x_{(\lfloor L \rfloor)}\right) $$dove:
- $\lfloor L \rfloor$ è la parte intera inferiore (floor(L));
- $\lceil L \rceil$ è la parte intera superiore (ceil(L)).
In Python possiamo implementare tali formule con il codice seguente:
def percentile_position(n:int, k:int):
"""Restituisce la posizione teorica del k-esimo percentile."""
return (k / 100) * (n + 1)
def percentile_value(data:np.ndarray, k:int):
"""
Calcola il k-esimo percentile usando la relativa formula di posizione:
L = (k / 100) * (n + 1)
Se L è intero:
Pk = x_(L)
Altrimenti:
Pk = x_floor + (L - L_floor) * (x_ceil - x_floor)
Le osservazioni vengono ordinate automaticamente.
"""
x = sorted(data)
n = len(x)
L = percentile_position(n, k)
# Gestione degli estremi
if L <= 1:
return x[0]
if L >= n:
return x[-1]
# Caso posizione intera
if L.is_integer():
return x[int(L) - 1]
# Caso interpolato
L_floor = math.floor(L)
L_ceil = math.ceil(L)
x_floor = x[L_floor - 1]
x_ceil = x[L_ceil - 1]
return x_floor + (L - L_floor) * (x_ceil - x_floor)
Ad esempio, se volessimo calcolare il $20°$ percentile, cioè il valore sotto il quale si trova circa il $20\%$ delle osservazioni:
# Esempio
data = [10, 7, 2, 5, 6, 3, 4, 9, 8, 1]
k = 20
L = percentile_position(len(data), k)
Pk = percentile_value(data, k)
print(f"Dati ordinati: ... {sorted(data)}")
print(f"k: ............... {k}")
print(f"Posizione L: ..... {L:.2f}")
print(f"P{k}: ............. {Pk:.2f}")
# Dati ordinati: ... [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# k: ............... 20
# Posizione L: ..... 2.20
# P20: ............. 2.20
In modo più semplice possiamo usare la funzione np.percentile(data, k) di Numpy,
che calcola il percentile di ordine k dei valori contenuti nell’array data:
import numpy as np
data = [10, 7, 2, 5, 6, 3, 4, 9, 8, 1]
k = 20
p_value = np.percentile(data, k)
print(f"Dati ordinati: ... {sorted(data)}")
print(f"k: ............... {k}")
print(f"P{k}: ............. {p_value:.2f}")
# Dati ordinati: ... [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# k: ............... 20
# P20: ............. 2.80
Quartili
I quartili sono misure di posizione che suddividono un insieme di dati ordinati in quattro parti uguali, ciascuna contenente circa il $25\%$ delle osservazioni.
Si distinguono tre quartili principali, indicati con Q1, Q2 e Q3:
- Q1 è il valore sotto il quale si trova circa il $25\%$ dei dati, e corrisponde al $25°$ percentile.
- Q2 è il valore che divide il dataset a metà (mediana), e corrisponde al $50°$ percentile.
- Q3 è il valore sotto il quale si trova circa il $75\%$ dei dati, e corrisponde al $75°$ percentile.

I quartili consentono di descrivere la distribuzione dei dati in modo sintetico ma informativo: Q2 individua la posizione centrale (mediana), mentre Q1 e Q3 delimitano la dispersione dei valori attorno alla mediana, e forniscono un riferimento utile per l’individuazione di eventuali outlier.
L’immagine seguente mostra i quartili per le distribuzioni uniformi, a campana, asimmetriche a destra e asimmetriche a sinistra:

I quartili possono essere calcolati utilizzando la formula fornita per il calcolo dei percentili, ma esiste una procedura più semplice. Supponiamo di avere il seguente dataset ordinato:
$$\{2, 4, 6, \color{green}{8, 10}, 12, 14, 16\}$$Q2 (Mediana):
gli elementi del dataset sono pari, la mediana viene calcolata come la media dei due elementi centrali, $8$ e $10$:
$Q2 = (8 + 10) / 2 = 9$Q1 (mediana della metà inferiore):
La metà inferiore del dataset è: ${2, \color{green}{4, 6}, 8}$. Quindi:
$Q1 = (4 + 6) / 2 = 5$Q3 (mediana della metà superiore):
La metà inferiore del dataset è: ${10, \color{green}{12, 14}, 16}$. Quindi:
$Q3 = (12 + 14) / 2 = 13$
In Python, possiamo calcolare un quartile usando lo stessoo algoritmo,
o, più semplicemente, riusando la funzione np.percentile(data, k)
di Numpy, già vista nella sezione dei percentili:
import numpy as np
def quantile(x):
"""Calcolo del quartile usando la formula semplificata basata sulla mediana."""
# Mediana (Q2)
q2 = np.median(x)
# Suddivisione nelle due metà
x_len = len(x)
x_low = x[:x_len // 2]
x_up = x[x_len // 2:]
# Quartili Q1 e Q3
q1 = np.median(x_low)
q3 = np.median(x_up)
return q1, q2, q3
def print_quartiles(label, quartiles):
print(label)
print(f"Q1 = {quartiles[0]}")
print(f"Q2 = {quartiles[1]}")
print(f"Q3 = {quartiles[2]}\n")
# Dataset ordinato
x = np.array([2, 4, 6, 8, 10, 12, 14, 16])
q1, q2, q3 = quantile(x)
print_quartiles("Metodo semplificato:", [q1, q2, q3])
# Q1 = 5.0; Q2 = 9.0; Q3 = 13.0
# Metodo 2 - np.percentile().
# Il parametro "q" specifica i percentili da calcolare
q_numpy = np.percentile(x, q=[25, 50, 75]) # method="median_unbiased"
print_quartiles("Metodo NumPy (percentile):", q_numpy)
# Q1 = 5.5; Q2 = 9.0; Q3 = 12.5
# In alternativa: np.quantile()
# Il parametro "q" rappresenta la posizione desiderata,
# espressa come una frazione compresa tra 0 e 1.
q_numpy2 = np.quantile(x, q=[0.25, 0.50, 0.75])
print_quartiles("Metodo NumPy (quantile):", q_numpy)
# Q1 = 5.5; Q2 = 9.0; Q3 = 12.5
Le funzioni np.percentile() e np.quantile(), invece, per impostazione predefinita
utilizzano un metodo basato sull’interpolazione lineare tra osservazioni adiacenti (metodo linear).
Per questo motivo restituiscono risultati diversi dalla funzione “fatta a mano”.
Se desideriamo che NumPy produca gli stessi risultati del metodo “mediana delle due metà”,
possiamo specificare un metodo diverso tramite il parametro method="hazen".
Intervallo Interquartile (IQR)
L’Intervallo Interquartile (IQR), o scarto interquartile, è una misura di dispersione che descrive quanto i dati sono distribuiti nella parte centrale di una distribuzione, ignorando i valori estremi. Proprio per questa caratteristica è considerato una misura robusta, cioè poco sensibile alla presenza di outlier.
In termini operativi, l’IQR è definito come la differenza tra il terzo e il primo quartile:
$$\text{IQR} = Q3 - Q1$$e rappresenta l’ampiezza dell’intervallo che contiene il 50% centrale dei dati:

A differenza di altre misure di dispersione, l’IQR si concentra esclusivamente sui valori più rappresentativi della distribuzione: esclude infatti il 25% più basso e il 25% più alto dei dati. Questo lo rende particolarmente utile quando sono presenti valori estremi, che potrebbero alterare significativamente altre misure (come il range o la deviazione standard). Ignorando tali valori, l’IQR fornisce una descrizione più stabile e realistica della variabilità “tipica” dei dati.
Dal punto di vista interpretativo:
un IQR basso indica che i dati sono concentrati attorno alla mediana Q2, suggerendo una distribuzione relativamente compatta e omogenea;
un IQR elevato segnala una maggiore dispersione nella parte centrale, indice di una distribuzione più variabile ed eterogenea:

Supponiamo di analizzare gli stipendi in un’azienda dove la maggior parte dei dipendenti guadagna mensilmente tra $1{,}500$€ e $2{,}500$€, mentre il CEO guadagna $5{,}000$€. Se ordinassimo tutti gli stipendi, noteremmo che i valori “centrali” si concentrano in un intervallo relativamente ristretto, mentre il valore del CEO si colloca molto distante dal resto dei dati. In questo contesto, l’IQR rappresenta l’ampiezza dell’intervallo che contiene il $50\%$ centrale degli stipendi.
Ad esempio, se $Q1 = 1{,}500$€ e $Q3 = 2{,}500$€, allora:
$$ \text{IQR} = 2{,}500 - 1{,}500 = 1{,}000 $$Questo significa che lo stipendio della metà centrale dei dipendenti è compreso in un intervallo di ampiezza pari a $1{,}000$€. Inoltre, possiamo notare come l’$\text{IQR}$ non sia necessariamente simmetrico rispetto alla mediana $Q2$:

L’aspetto più importante è che l’$IQR$ è una misura robusta: non viene influenzato da valori estremi come lo stipendio del CEO. Infatti, mentre la media degli stipendi risulterebbe fortemente aumentata dalla presenza di questo valore anomalo, l’$IQR$ continua a descrivere in modo fedele la variabilità degli stipendi “tipici”.
Un Paio di Esempi
Riprendiamo l’esempio precedente sui quartili. Supponiamo di avere il seguente dataset ordinato:
$$\{2, 4, 6, \color{green}{8, 10}, 12, 14, 16\}$$Q2 (Mediana):
gli elementi del dataset sono pari, la mediana viene calcolata come la media dei due elementi centrali, $8$ e $10$:
$Q2 = (8 + 10) / 2 = 9$Q1 (mediana della metà inferiore):
La metà inferiore del dataset è: ${2, \color{green}{4, 6}, 8}$. Quindi:
$Q1 = (4 + 6) / 2 = 5$Q3 (mediana della metà superiore):
La metà inferiore del dataset è: ${10, \color{green}{12, 14}, 16}$. Quindi:
$Q3 = (12 + 14) / 2 = 13$IQR:
Come da definizione:
$\text{IQR} = Q3 - Q1 = 13 - 5 = 8$
Ora consideriamo questo dataset ordinato, con un numero dispari di elementi: $$\{1, 2, 3, \color{green}{4}, 5, 6, 7\}$$
- Q2 = $4$
- Q1 = $\text{med}({1, \color{green}{2}, 3}) = 2$
- Q3 = $\text{med}({5, \color{green}{6}, 7}) = 6$
- IQR = $Q3 - Q1 = 6 - 2 = 4$