Vai al contenuto principale

Capire asimmetria e curtosi e come tracciarle

Una guida visiva completa su asimmetria/curtosi, su come influenzano le distribuzioni e, in definitiva, il tuo progetto di data science.
Aggiornato 3 giu 2026  · 10 min leggi

Dopo aver raccolto i dati e aver passato ore a ripulirli, puoi finalmente iniziare a esplorarli! Questa fase, spesso chiamata Exploratory Data Analysis (EDA), è probabilmente il passaggio più importante in un progetto di dati. Le intuizioni ricavate dall’EDA influenzano tutto ciò che viene dopo.

Per esempio, uno dei passaggi imprescindibili nell’EDA è controllare le forme delle distribuzioni. Identificare correttamente la forma influenza molte decisioni successive nel progetto, come:

  • Ulteriori passaggi di pre-processamento
  • Se eseguire o meno il rilevamento degli outlier e magari la loro rimozione
  • Trasformazioni o scaling delle feature
  • Selezione delle feature
  • Scelta dell’algoritmo

e così via. Sebbene esistano visualizzazioni per farlo, servono metriche più affidabili per quantificare diverse caratteristiche delle distribuzioni. Due di queste metriche sono asimmetria e curtosi. Puoi usarle per valutare quanto le tue distribuzioni assomigliano a una distribuzione normale perfetta.

Al termine di questo articolo, imparerai nel dettaglio:

  • Cosa sono asimmetria e curtosi
  • I tipi di asimmetria e di curtosi
  • L’effetto di asimmetria e curtosi sui modelli di machine learning
  • Il calcolo di asimmetria e curtosi in Python manualmente e con pacchetti di terze parti
  • La visualizzazione delle distribuzioni per verificare i punteggi di asimmetria e curtosi (sezione completa e divertente)

Iniziamo!

Che cos’è l’asimmetria?

Vediamo la distribuzione normale ovunque: misure del corpo umano, pesi degli oggetti, punteggi del QI, risultati dei test, o persino in palestra:

Un’immagine di una macchina a pesi in palestra. I fori dei perni nei pesi nel loro insieme formano una forma a distribuzione normale a causa dell’uso prolungato nel tempo.

Fonte

Oltre a essere la distribuzione preferita dalla natura, è amata universalmente da quasi tutti gli algoritmi di machine learning. Alcuni la desiderano per migliorare e stabilizzare le prestazioni, altri si rifiutano del tutto di funzionare bene con qualcosa di diverso dalla distribuzione normale (sì, sto parlando con voi, modelli lineari).

Quindi, per soddisfare il bisogno di normalità degli algoritmi, ci serve un modo per misurare quanto le nostre distribuzioni siano simili (o dissimili) rispetto alla curva perfetta a campana.

Curva a campana perfetta di una distribuzione normale.

Partiamo dalle code. In una distribuzione normale perfetta, le code hanno uguale lunghezza. Quando però c’è asimmetria tra le code, che dà un aspetto inclinato, schiacciato da un lato, diciamo che è asimmetrica. E, come avrai intuito, misuriamo il grado di questa asimmetria con l’asimettria (skewness).

Diversi tipi di asimmetria ai lati di una distribuzione normale non asimmetrica.

Classificare e misurare correttamente l’asimmetria offre indicazioni su come i valori sono distribuiti attorno alla media e influenza la scelta delle tecniche statistiche e delle trasformazioni dei dati. Per esempio, distribuzioni molto asimmetriche possono trarre vantaggio da tecniche di normalizzazione o scaling per farle assomigliare di più a una distribuzione normale. Questo può aiutare le prestazioni del modello.

Tipi di asimmetria

Esistono tre tipi di asimmetria: positiva, negativa e nulla.

Partiamo dall’ultima. Una distribuzione con asimmetria nulla ha le seguenti caratteristiche:

  • Distribuzione simmetrica con valori equamente centrati attorno alla media.
  • Nessuna pendenza, inclinazione o coda da un lato o dall’altro.
  • Media, mediana e moda si trovano tutte nel punto centrale.

Una distribuzione normale (asimmetria zero) con media, mediana e moda tutte allineate su un’unica linea.

In pratica, media, mediana e moda potrebbero non formare una linea retta perfettamente sovrapposta. Potrebbero essere leggermente distanti tra loro, ma la differenza sarebbe troppo piccola per contare.

In una distribuzione con asimmetria positiva (a destra):

  • La coda destra della distribuzione è più lunga o più spessa di quella sinistra.
  • La media è maggiore della mediana e la moda è inferiore sia alla media sia alla mediana.
  • I valori più bassi sono raggruppati nella “collina” della distribuzione, mentre i valori estremi sono nella lunga coda destra.
  • È nota anche come distribuzione con coda a destra.

Distribuzione con asimmetria a destra con media, mediana e moda annotate.

In una distribuzione con asimmetria negativa (a sinistra):

  • La coda sinistra della distribuzione è più lunga o più spessa di quella destra.
  • La media è inferiore alla mediana e la moda è maggiore sia della media sia della mediana.
  • I valori più alti sono raggruppati nella “collina” della distribuzione, mentre i valori estremi sono nella lunga coda sinistra.
  • È nota anche come distribuzione con coda a sinistra.

Distribuzione con asimmetria a sinistra con media, mediana e moda annotate

Per ricordare la differenza tra asimmetria positiva e negativa, pensa così: se vuoi aumentare la media di una distribuzione, devi aggiungere alla distribuzione valori molto più alti della media. Per abbassare la media, devi fare il contrario — introdurre valori molto più bassi della media. Quindi, se la maggior parte dei valori estremi è superiore alla media, l’asimettria sarà positiva perché aumentano la media. Se la maggior parte dei valori estremi è inferiore alla media, l’asimettria è negativa perché abbassano la media.

Come calcolare l’asimmetria in Python

Ci sono molti modi per calcolare l’asimmetria, ma il più semplice è il secondo coefficiente di asimmetria di Pearson, noto anche come asimmetria rispetto alla mediana.

image.png

Implementiamo la formula manualmente in Python:

import numpy as np
import pandas as pd
import seaborn as sns

# Example dataset
diamonds = sns.load_dataset("diamonds")
diamond_prices = diamonds["price"]

mean_price = diamond_prices.mean()
median_price = diamond_prices.median()
std = diamond_prices.std()

skewness = (3 * (mean_price - median_price)) / std

>>> print(
   f"The Pierson's second skewness score of diamond prices distribution is {skewness:.5f}"
)

The Pierson's second skewness score of diamond prices distribution is 1.15189

Un’altra formula, molto influenzata dai lavori di Karl Pearson, è la formula basata sui momenti per approssimare l’asimmetria. È più affidabile ed è la seguente:

Un’altra formula per calcolare l’asimmetria usando i momenti

Dove:

  • n rappresenta il numero di valori in una distribuzione
  • x_i indica ciascun punto dati

Implementiamola anche in Python:

def moment_based_skew(distribution):
   n = len(distribution)
   mean = np.mean(distribution)
   std = np.std(distribution)

   # Divide the formula into two parts
   first_part = n / ((n - 1) * (n - 2))
   second_part = np.sum(((distribution - mean) / std) ** 3)

   skewness = first_part * second_part

   return skewness

>>> moment_based_skew(diamond_prices)
1.618440289857168

Se non vuoi calcolare l’asimmetria manualmente (come me), puoi usare i metodi integrati di pandas o scipy:

# Pandas version
diamond_prices.skew()
1.618395283383529

# SciPy version
from scipy.stats import skew

skew(diamond_prices)
1.6183502776053016

Anche se tutte le formule per approssimare l’asimmetria restituiscono punteggi diversi, le differenze sono troppo piccole per essere significative o cambiare la classificazione dell’asimmetria. Per esempio, tutti i metodi usati qui adottano formule diverse “sotto il cofano”, ma i risultati sono molto vicini.

Una volta calcolata l’asimmetria, puoi classificarne il grado:

  • (-0.5, 0.5) — bassa o approssimativamente simmetrica.
  • (-1, -0.5) U (0.5, 1) — moderatamente asimmetrica.
  • Oltre -1 e 1 — Fortemente asimmetrica.

Che cos’è la curtosi e quali sono i suoi tipi?

Mentre l’asimmetria si concentra sulla dispersione (le code) della distribuzione normale, la curtosi si concentra maggiormente sull’altezza. Ci dice quanto è appuntita o piatta la nostra distribuzione normale (o simile alla normale). Il termine, che dal greco significa curvato o arcuato, fu coniato, non a sorpresa, dal matematico britannico Karl Pearson (che ha dedicato la vita allo studio delle distribuzioni di probabilità).

Un’alta curtosi indica:

  • Forte appuntitezza al centro della distribuzione.
  • Più valori concentrati attorno alla media rispetto alla distribuzione normale.
  • Code più pesanti a causa di una maggiore concentrazione di valori estremi o outlier nelle code.
  • Maggiore probabilità di eventi estremi.

D’altra parte, una bassa curtosi indica:

  • Picco piatto.
  • Meno valori concentrati attorno alla media ma comunque più che nella distribuzione normale.
  • Code più leggere.
  • Minore probabilità di eventi estremi.

A seconda del grado, le distribuzioni presentano tre tipi di curtosi:

  1. Distribuzione mesocurtica (curtosi = 3, curtosi in eccesso = 0): distribuzione normale perfetta o molto vicina.
  2. Distribuzione leptocurtica (curtosi > 3, curtosi in eccesso > 0): picco appuntito, code pesanti
  3. Distribuzione platicurtica (curtosi < 3, curtosi in eccesso < 0): picco piatto, code leggere

Tre diversi tipi di distribuzioni: leptocurtica (curtosi alta), mesocurtica (nessuna curtosi) e platicurtica (curtosi bassa)

Nota che qui, la curtosi in eccesso è definita come curtosi - 3, trattando la curtosi della distribuzione normale come 0. In questo modo, i punteggi di curtosi sono più interpretabili.

Come calcolare la curtosi in Python

Puoi calcolare la curtosi in Python allo stesso modo dell’asimettria usando pandas o SciPy:

from scipy.stats import kurtosis

kurtosis(diamond_prices)
2.177382669056634

Pandas offre due funzioni per la curtosi: kurt e kurtosis. La prima è esclusiva delle Series di Pandas, mentre l’altra può essere usata sui DataFrame.

diamond_prices.kurt()
2.17769575924869

# Select numeric features and calculate kurtosis
diamonds.select_dtypes(include="number").kurtosis()
carat     1.256635
depth     5.739415
table     2.801857
price     2.177696
x        -0.618161
y        91.214557
z        47.086619
dtype: float64

Di nuovo, i numeri differiscono per la distribuzione perché pandas e SciPy usano formule diverse.

Se vuoi un calcolo manuale della curtosi, puoi usare la seguente formula:

La formula per calcolare la curtosi usando i momenti, influenzata da Karl Pearson

Dove:

  • n rappresenta il numero di osservazioni nel dataset
  • x_i indica ciascun singolo punto dati

Implementeremo di nuovo la formula all’interno di una funzione:

def moment_based_kurtosis(distribution):
   n = len(distribution)
   mean = np.mean(distribution)
   std = np.std(distribution)

   kurtosis = (1 / n) * sum(((distribution - mean) / std) ** 4) - 3

   return kurtosis

>>> moment_based_kurtosis(diamond_prices)
2.1773826690576463

E scopriamo che i prezzi dei diamanti hanno una curtosi in eccesso di 2,18, il che significa che, se tracciamo la distribuzione, avrà un picco più appuntito rispetto a una distribuzione normale.

Quindi, facciamolo!

Visualizzare asimmetria e curtosi in Python

Una delle migliori visualizzazioni per vedere la forma e quindi l’asimmetria e la curtosi delle distribuzioni è il grafico della stima della densità tramite kernel (KDE). È disponibile in Seaborn:

import matplotlib.pyplot as plt

sns.kdeplot(diamond_prices)

plt.title("KDE plot of diamond prices")
plt.xlabel("Price ($)")

Un grafico KDE dei prezzi dei diamanti

Questo grafico è coerente con i numeri visti finora: la distribuzione ha una lunga coda destra, che indica un’asimettria positiva, e un picco molto appuntito, che corrisponde a una curtosi alta.

Il KDE non è l’unico grafico per vedere la forma. Possiamo usare anche gli istogrammi:

sns.histplot(diamonds["carat"])

plt.xlabel("Carat")
plt.title("A histogram of the carat of diamonds")

Un istogramma dei carati dei diamanti

Lo svantaggio degli istogrammi è che devi scegliere tu il numero di bin (il numero di barre). Qui ci sono troppe barre che creano rumore nella visuale — non riusciamo a definire chiaramente la forma. Quindi, riduciamo il numero di bin:

sns.histplot(diamonds["carat"], bins=25)

plt.xlabel("Carat")
plt.title("A histogram of the carat of diamonds")

Un istogramma dei carati dei diamanti con meno bin

Ora la forma è più definita, ma possiamo migliorarla ancora. Impostando kde=True dentro histplot, possiamo tracciare un KDE della distribuzione sopra le barre:

sns.histplot(diamonds["carat"], bins=25, kde=True)

plt.xlabel("Carat")
plt.title("A histogram of the carat of diamonds")

Un istogramma sovrapposto a un grafico KDE dei carati dei diamanti

La linea KDE sovrapposta appare frastagliata, non la curva liscia che ci permette di vedere la forma generale. Il motivo è che la distribuzione dei carati è naturalmente irregolare e lontana dalla distribuzione normale.

Possiamo però ridurre la sensibilità del KDE a queste fluttuazioni regolando l’ampiezza di banda. Si fa con il parametro bw_adjust, che per impostazione predefinita è 1:

# Change the bandwidth from 1 to 3
sns.kdeplot(diamonds["carat"], bw_adjust=3, color="red")

plt.title("KDE of diamond carats");

Un KDE dei carati dei diamanti con ampiezza di banda più alta

Questa versione è molto meno frastagliata rispetto al KDE sovrapposto. Per regolare l’ampiezza di banda del KDE quando usi un istogramma con KDE sovrapposto, puoi usare il parametro kde_kws:

ax = sns.histplot(
   diamonds["carat"],
   kde=True,
   kde_kws=dict(bw_adjust=3),
   bins=25,
)

plt.title("An overlaid histogram of diamond carats");

Un istogramma sovrapposto a un grafico KDE con ampiezza di banda regolata.

kde_kws accetta qualsiasi parametro previsto dalla funzione kdeplot che controlli il calcolo del KDE.

Un trucco che puoi usare quando tracci i KDE è rimuovere tutto tranne la linea KDE. Poiché lo scopo principale di un KDE è vedere la forma della distribuzione, altri dettagli del grafico come i tick degli assi, le cornici e le etichette a volte sono superflui:

sns.kdeplot(diamond_prices, color="red")

# Remove the spine from three sides
sns.despine(top=True, right=True, left=True)

# Remove the ticks and ticklabels
plt.xticks([])
plt.yticks([])
plt.ylabel("")
plt.xlabel("")

# Set a title
plt.title("Diamond prices", fontdict=dict(fontsize=20));

Un grafico KDE con tutto rimosso - tranne la linea KDE e il titolo.

Questo grafico è molto più pulito. Puoi migliorarlo ulteriormente aggiungendo linee per indicare la posizione di media, mediana e moda:

sns.kdeplot(diamond_prices, color="red")

sns.despine(top=True, right=True, left=True)
plt.xticks([])
plt.yticks([])
plt.ylabel("")
plt.xlabel("")
plt.title("Diamond prices", fontdict=dict(fontsize=20))

# Find the mean, median, mode
mean_price = diamonds["price"].mean()
median_price = diamonds["price"].median()
mode_price = diamonds["price"].mode().squeeze()

# Add vertical lines at the position of mean, median, mode
plt.axvline(mean_price, label="Mean")
plt.axvline(median_price, color="black", label="Median")
plt.axvline(mode_price, color="green", label="Mode")

plt.legend();

Un grafico KDE con solo la linea KDE, il titolo e media, mediana e moda annotate.

Questo grafico conferma quanto discusso nella sezione sui tipi di asimmetria: in una distribuzione con asimmetria positiva, la media è superiore alla mediana e la moda è inferiore sia alla media sia alla mediana.

Conclusione

Asimmetria e curtosi, spesso trascurate nell’Exploratory Data Analysis, rivelano informazioni importanti sulla natura delle distribuzioni.

L’asimettria indica l’inclinazione dei dati, verso sinistra o destra, rivelandone l’eventuale asimmetria. L’asimmetria positiva implica una coda che si allunga a destra, mentre quella negativa va nella direzione opposta.

La curtosi riguarda picchi e code. Una curtosi alta rende i picchi più appuntiti e appesantisce le code, mentre una curtosi bassa allarga i dati, alleggerendo le code.

Se vuoi approfondire asimmetria e curtosi, dai un’occhiata a questi ottimi corsi di analisi quantitativa tenuti da esperti del settore su DataCamp:


Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Sono un creator di contenuti sulla data science con oltre 2 anni di esperienza e uno dei profili con più seguito su Medium. Mi piace scrivere articoli dettagliati su AI e ML con un pizzico di sarcasmo, perché qualcosa bisogna pur fare per renderli un po' meno noiosi. Ho pubblicato più di 130 articoli e anche un corso su DataCamp, con un altro in arrivo. I miei contenuti sono stati visti da oltre 5 milioni di occhi, e 20.000 di loro sono diventati follower sia su Medium che su LinkedIn. 

Argomenti

Scopri di più! 

Corso

Introduzione alla gestione del rischio di portafoglio in Python

4 h
29K
Vedi dettagliRight Arrow
Inizia il corso
Mostra altroRight Arrow
Correlato

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

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

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