W3docs

Distribuzione dei Dati nel Machine Learning

Scopri come funzionano le distribuzioni dei dati in Python: distribuzioni normale, asimmetrica e uniforme, come rilevarle e perché sono importanti.

La distribuzione dei dati descrive come i valori sono dispersi all'interno di un dataset — quali valori sono comuni, quali sono rari e quanto si estendono dal centro. Prima di addestrare qualsiasi modello di machine learning, comprendere la distribuzione dei dati ti aiuta a scegliere l'algoritmo giusto, rilevare anomalie, decidere se scalare o trasformare le feature ed evitare distorsioni nascoste nelle previsioni.

Questo capitolo tratta le forme di distribuzione più comuni, come misurarle in Python usando NumPy e SciPy, e cosa significa ciascuna distribuzione per le tue decisioni di modellazione.

Cos'è la Distribuzione dei Dati?

Una distribuzione dei dati è il pattern con cui ogni valore (o intervallo di valori) appare in un dataset. Quando si visualizza una distribuzione, si ottiene tipicamente una curva o un istogramma la cui forma rivela molte informazioni sui dati sottostanti.

Le tre proprietà che definiscono qualsiasi distribuzione sono:

  • Centro — dove si concentra la maggior parte dei valori (misurato da media, mediana e moda)
  • Dispersione — quanto i valori si discostano dal centro (misurata dalla deviazione standard e dall'intervallo interquartile)
  • Forma — se la distribuzione è simmetrica, asimmetrica o piatta

Comprendere tutte e tre è indispensabile prima di inserire i dati in un modello.

Tipi di Distribuzione Comuni

Distribuzione Normale

La distribuzione normale (chiamata anche distribuzione gaussiana) è la distribuzione più importante in statistica e machine learning. Il suo istogramma forma una curva a campana simmetrica: i valori si concentrano attorno alla media e la frequenza diminuisce in modo uniforme su entrambi i lati.

Proprietà principali:

  • Media, mediana e moda sono tutte uguali.
  • Circa il 68% dei valori cade entro una deviazione standard dalla media, il 95% entro due e il 99,7% entro tre (regola empirica).
  • Definita interamente da due parametri: media (μ) e deviazione standard (σ).

Molti fenomeni del mondo reale approssimano una distribuzione normale — l'altezza degli esseri umani, gli errori di misurazione e i punteggi QI sono esempi classici. Algoritmi come l'analisi discriminante lineare, il Gaussian naive Bayes e la regressione lineare assumono (o traggono vantaggio da) feature distribuite normalmente.

import numpy as np
from scipy import stats

# Simulate 1 000 adult heights (cm) drawn from a normal distribution
rng = np.random.default_rng(seed=42)
heights = rng.normal(loc=170, scale=10, size=1000)

print(f"Mean:   {np.mean(heights):.1f} cm")
print(f"Std:    {np.std(heights):.1f} cm")

# Verify the empirical rule
within_1_std = np.sum(np.abs(heights - 170) < 10) / 1000 * 100
within_2_std = np.sum(np.abs(heights - 170) < 20) / 1000 * 100
within_3_std = np.sum(np.abs(heights - 170) < 30) / 1000 * 100

print(f"Within 1 std: {within_1_std:.1f}%  (expected ~68%)")
print(f"Within 2 std: {within_2_std:.1f}%  (expected ~95%)")
print(f"Within 3 std: {within_3_std:.1f}%  (expected ~99.7%)")

Output:

Mean:   169.7 cm
Std:    9.9 cm
Within 1 std: 68.8%  (expected ~68%)
Within 2 std: 95.7%  (expected ~95%)
Within 3 std: 99.8%  (expected ~99.7%)

Distribuzione Asimmetrica

Una distribuzione asimmetrica è non simmetrica: una coda è più lunga dell'altra. L'asimmetria è misurata dalla statistica di skewness — valori positivi indicano un'asimmetria a destra (positiva), valori negativi indicano un'asimmetria a sinistra (negativa) e valori prossimi allo zero indicano una sostanziale simmetria.

Asimmetrica positiva (coda destra): la coda si estende verso destra. La media è trascinata sopra la mediana da un piccolo numero di valori molto elevati. I redditi e i prezzi delle case ne sono esempi tipici — una manciata di percettori molto alti o proprietà molto costose trascinano la media ben al di sopra della mediana.

Asimmetrica negativa (coda sinistra): la coda si estende verso sinistra. I punteggi degli esami in un test facile mostrano spesso questo pattern — la maggior parte degli studenti ottiene punteggi vicini al massimo, ma alcuni ottengono punteggi molto bassi.

import numpy as np
from scipy import stats

# Right-skewed: a small number of very high values pull the mean up
salaries = np.array([30000, 32000, 34000, 35000, 36000, 38000,
                     40000, 42000, 45000, 55000, 70000, 120000, 200000])

print("--- Salary distribution ---")
print(f"Mean:     {np.mean(salaries):.0f}")    # pulled up by outliers
print(f"Median:   {np.median(salaries):.0f}")  # more representative center
print(f"Skewness: {stats.skew(salaries):.2f}") # positive = right skew

# Left-skewed: most values are high, a few are very low
exam_scores = np.array([40, 68, 75, 80, 82, 85, 88, 90, 91, 92, 93, 95, 98])
print("\n--- Exam score distribution ---")
print(f"Mean:     {np.mean(exam_scores):.1f}")
print(f"Median:   {np.median(exam_scores):.1f}")
print(f"Skewness: {stats.skew(exam_scores):.2f}") # negative = left skew

Output:

--- Salary distribution ---
Mean:     59769
Median:   40000
Skewness: 2.16

--- Exam score distribution ---
Mean:     82.8
Median:   88.0
Skewness: -1.77

Quando è presente un'asimmetria, la media è una misura del centro fuorviante. La mediana è generalmente una statistica riassuntiva migliore per i dati asimmetrici.

Distribuzione Uniforme

In una distribuzione uniforme, ogni valore (o intervallo di valori) è ugualmente probabile. Un dado a sei facce equo produce una distribuzione uniforme discreta; estrarre casualmente un numero in virgola mobile tra 0 e 1 produce una distribuzione uniforme continua.

import numpy as np

rng = np.random.default_rng(seed=42)
# Continuous uniform distribution between 0 and 1
uniform_data = rng.uniform(low=0, high=1, size=10000)

print(f"Mean:   {np.mean(uniform_data):.3f}  (expected 0.500)")
print(f"Std:    {np.std(uniform_data):.3f}   (expected ~0.289)")
print(f"Min:    {np.min(uniform_data):.3f}")
print(f"Max:    {np.max(uniform_data):.3f}")

Output:

Mean:   0.497  (expected 0.500)
Std:    0.288   (expected ~0.289)
Min:    0.000
Max:    1.000

Le distribuzioni uniformi compaiono nel campionamento casuale, nell'augmentation dei dati e come prior nei modelli bayesiani.

Riepilogare una Distribuzione in Python

Prima della modellazione, calcola sempre un rapido sommario di ciascuna feature. NumPy e SciPy insieme coprono le statistiche principali:

import numpy as np
from scipy import stats

data = np.array([12, 15, 14, 10, 18, 14, 13, 16, 14, 12])

print("--- Distribution Summary ---")
print(f"Mean:     {np.mean(data):.1f}")
print(f"Median:   {np.median(data):.1f}")
print(f"Std:      {np.std(data, ddof=1):.2f}")   # sample std deviation
print(f"Min:      {np.min(data)}")
print(f"Max:      {np.max(data)}")
print(f"Skewness: {stats.skew(data):.3f}")        # near 0 = symmetric

Output:

--- Distribution Summary ---
Mean:     13.8
Median:   14.0
Std:      2.25
Min:      10
Max:      18
Skewness: 0.200

Un valore di skewness prossimo a 0.200 indica che i dati sono approssimativamente simmetrici — nessuna forte asimmetria in nessuna direzione.

Test di Normalità

Alcuni algoritmi assumono esplicitamente che le feature siano distribuite normalmente. Il test di Shapiro-Wilk è il test più affidabile per campioni piccoli (n < 5 000). Restituisce una statistica W e un p-value. Un p-value maggiore di 0,05 significa che non puoi rifiutare l'ipotesi che i dati siano normali.

import numpy as np
from scipy import stats

rng = np.random.default_rng(seed=42)

# Sample from a normal distribution
normal_sample = rng.normal(loc=0, scale=1, size=50)
stat, p = stats.shapiro(normal_sample)
print(f"Shapiro-Wilk: W={stat:.3f}, p={p:.3f}")
if p > 0.05:
    print("Data appears to be normally distributed.")
else:
    print("Data does not appear to be normally distributed.")

Output:

Shapiro-Wilk: W=0.984, p=0.730
Data appears to be normally distributed.

Quando usarlo: applica il test di Shapiro-Wilk quando le assunzioni di un modello richiedono esplicitamente la normalità — ad esempio, prima di usare un t-test parametrico o l'analisi discriminante lineare. Molti algoritmi moderni (gradient boosting, random forest, reti neurali) non sono sensibili alla forma della distribuzione delle feature, quindi non è sempre necessario questo test.

Perché la Forma della Distribuzione è Importante per la Modellazione

SituazioneCosa significaCosa fare
Feature normaliLe assunzioni standard sono valideUsa modelli parametrici così come sono
Feature con asimmetria positivaLa media è inflazionata; i valori anomali dominanoApplica la trasformazione logaritmica o della radice quadrata
Feature con asimmetria negativaI valori bassi sono outlierApplica la trasformazione quadratica o di riflessione
Feature uniformiNessuna concentrazione centraleSpesso va bene; normalizza per i modelli basati sulla distanza
Feature multimodaliPiù clusterConsidera di suddividere i dati o di usare un passaggio di clustering

Gestire i Dati Asimmetrici con la Trasformazione Logaritmica

Un rimedio comune per i dati con asimmetria positiva è la trasformazione logaritmica, che comprime i valori grandi e espande quelli piccoli, producendo spesso una distribuzione più vicina alla normale.

import numpy as np
from scipy import stats

rng = np.random.default_rng(seed=7)
# Simulate log-normally distributed incomes (a common real-world pattern)
incomes = rng.lognormal(mean=10.5, sigma=0.5, size=1000)

print(f"Before transform — skewness: {stats.skew(incomes):.2f}")
log_incomes = np.log(incomes)
print(f"After log transform — skewness: {stats.skew(log_incomes):.2f}")

Output:

Before transform — skewness: 1.44
After log transform — skewness: 0.01

Dopo la trasformazione logaritmica, la skewness scende da 1.44 a quasi zero, rendendo i dati molto più adatti ai modelli che assumono la normalità.

Nota: la trasformazione logaritmica richiede che tutti i valori siano strettamente positivi. Aggiungi una piccola costante (es. np.log(x + 1)) se i tuoi dati contengono zeri.

Visualizzare la Distribuzione dei Dati

La visualizzazione è il modo più rapido per ispezionare una distribuzione. Un istogramma divide i valori in intervalli e mostra quante osservazioni ricadono in ciascun intervallo. Usa gli istogrammi di Matplotlib per crearli:

import numpy as np
import matplotlib.pyplot as plt

rng = np.random.default_rng(seed=42)
data = rng.normal(loc=170, scale=10, size=500)

plt.figure(figsize=(8, 4))
plt.hist(data, bins=30, color='steelblue', edgecolor='white')
plt.title("Height Distribution (Normal)")
plt.xlabel("Height (cm)")
plt.ylabel("Frequency")
plt.tight_layout()
plt.show()

Per una panoramica più rapida su più feature contemporaneamente, usa uno scatter plot per cercare relazioni tra le distribuzioni.

Distribuzione e Scaling delle Feature

Se le tue feature hanno distribuzioni o scale molto diverse, gli algoritmi basati sulla distanza (k-nearest neighbours, SVM, k-means clustering) saranno dominati dalle feature con l'intervallo più ampio. Lo scaling delle feature è la soluzione standard: StandardScaler normalizza ciascuna feature a una media di 0 e deviazione standard di 1, mentre MinMaxScaler comprime i valori in [0, 1].

Scegli lo scaler in base alla distribuzione sottostante:

  • Distribuzione normale → StandardScaler (rimuove la media, scala a varianza unitaria)
  • Distribuzione uniforme o limitata → MinMaxScaler (preserva la forma)
  • Fortemente asimmetrica con outlier → RobustScaler (usa mediana e IQR, ignorando i valori estremi)
  • Distribuzione normale: curva a campana simmetrica; media ≈ mediana; adatta ai modelli parametrici.
  • Distribuzione asimmetrica: non simmetrica; la media è trascinata verso la coda; le trasformazioni logaritmiche o di potenza possono ridurre l'asimmetria.
  • Distribuzione uniforme: tutti i valori ugualmente probabili; appare nel campionamento casuale e come prior non informativi.
  • Usa scipy.stats.skew() per misurare l'asimmetria e scipy.stats.shapiro() per testare formalmente la normalità.
  • Ispeziona sempre le distribuzioni prima della modellazione — la forma influenza la scelta dell'algoritmo, il modo in cui trasformare le feature e la strategia di scaling da applicare.

Successivamente, esplora la Distribuzione Normale dei Dati per un'analisi più approfondita della distribuzione gaussiana e su come generarla e utilizzarla con SciPy.

Was this page helpful?