Distribución Normal de Datos
Aprende la distribución normal (gaussiana) en Python: PDF, CDF, puntuaciones Z, regla empírica, pruebas de normalidad y cuándo usar transformaciones logarítmicas.
La distribución normal (también llamada distribución gaussiana) es la distribución de probabilidad más importante en estadística y aprendizaje automático. Comprenderla en profundidad — no solo reconocer su forma de campana, sino saber cómo medirla, verificarla y trabajar con ella en Python — te brinda una base sólida para la preparación de datos, la selección de modelos y la interpretación de resultados.
Este capítulo cubre:
- Qué es la distribución normal y por qué importa su forma
- La regla empírica (68–95–99.7) y cómo verificarla
- Generar datos con distribución normal usando NumPy
- Evaluar la función de densidad de probabilidad (PDF) y la función de distribución acumulada (CDF) con SciPy
- Calcular e interpretar puntuaciones Z
- Comprobar si los datos tienen distribución normal
- Qué hacer cuando los datos no son normales
¿Qué Es la Distribución Normal?
Una distribución de probabilidad describe la probabilidad de que cada valor de un conjunto de datos aparezca. La distribución normal es una distribución continua, simétrica y en forma de campana definida por dos parámetros:
- Media (μ) — el centro de la campana; donde se sitúa el pico
- Desviación estándar (σ) — qué tan ancha o estrecha es la campana; un σ mayor dispersa los valores más lejos del centro
Dado que la curva es simétrica respecto a la media, la media, la mediana y la moda son todas iguales en una distribución perfectamente normal.
La fórmula de la función de densidad de probabilidad es:
f(x) = (1 / (σ√(2π))) × e^(−(x−μ)² / (2σ²))No es necesario aplicar esta fórmula a mano — stats.norm de SciPy se encarga de ello — pero es útil saber que la forma depende únicamente de μ y σ.
La Regla Empírica (68–95–99.7)
Una de las propiedades más prácticas de la distribución normal es la regla empírica, también llamada regla 68–95–99.7:
| Rango desde la media | Porcentaje de valores |
|---|---|
| Dentro de ±1 desviación estándar | ~68% |
| Dentro de ±2 desviaciones estándar | ~95% |
| Dentro de ±3 desviaciones estándar | ~99.7% |
Esto significa que en un conjunto de datos con distribución normal, casi todos los valores se encuentran dentro de tres desviaciones estándar de la media. Los valores más allá de ±3σ son genuinamente raros — aproximadamente 1 de cada 370 observaciones.
El siguiente ejemplo simula 10 000 valores de una distribución normal estándar (μ=0, σ=1) y verifica la regla:
import numpy as np
rng = np.random.default_rng(seed=42)
mu, sigma = 0, 1
data = rng.normal(loc=mu, scale=sigma, size=10000)
w1 = np.mean(np.abs(data - mu) < 1 * sigma) * 100
w2 = np.mean(np.abs(data - mu) < 2 * sigma) * 100
w3 = np.mean(np.abs(data - mu) < 3 * sigma) * 100
print(f"Within 1 std: {w1:.1f}% (expected ~68%)")
print(f"Within 2 std: {w2:.1f}% (expected ~95%)")
print(f"Within 3 std: {w3:.1f}% (expected ~99.7%)")Salida:
Within 1 std: 67.8% (expected ~68%)
Within 2 std: 95.4% (expected ~95%)
Within 3 std: 99.7% (expected ~99.7%)La regla empírica es inmediatamente útil: si una puntuación de un examen está más de dos desviaciones estándar por encima de la media, se encuentra en el ~2.5% superior de todas las puntuaciones.
Generar Datos con Distribución Normal usando NumPy
El generador de números aleatorios de NumPy produce muestras que aproximan una distribución normal. El método rng.normal() acepta la media (loc), la desviación estándar (scale) y el número de muestras (size):
import numpy as np
rng = np.random.default_rng(seed=7)
# Simulate IQ scores: mean=100, std=15
samples = rng.normal(loc=100, scale=15, size=1000)
print(f"Sample mean: {samples.mean():.1f}")
print(f"Sample std: {samples.std():.1f}")
print(f"Min: {samples.min():.1f}")
print(f"Max: {samples.max():.1f}")
print(f"Sample size: {len(samples)}")Salida:
Sample mean: 98.9
Sample std: 14.1
Min: 51.2
Max: 138.6
Sample size: 1000La media y la desviación estándar de la muestra están cerca — pero no exactamente — de 100 y 15, porque una muestra finita tiene variación aleatoria natural. Con 10 000 muestras, las estimaciones convergen más cerca de los parámetros verdaderos.
¿Por qué usar una semilla? Pasar seed=7 a default_rng hace que los resultados sean reproducibles. Cualquiera que ejecute el mismo código obtiene los mismos números, lo cual es esencial para depurar y compartir resultados. La interfaz default_rng (introducida en NumPy 1.17) es preferible a la antigua np.random.normal() porque evita el estado global compartido.
Evaluar la PDF y la CDF con SciPy
Función de Densidad de Probabilidad (PDF)
La PDF indica la probabilidad relativa de un valor. Un valor de PDF más alto en x significa que x tiene más probabilidad de ocurrir. Para una distribución normal, el pico está en la media:
from scipy import stats
mu, sigma = 0, 1
x_values = [-2, -1, 0, 1, 2]
for x in x_values:
pdf = stats.norm.pdf(x, loc=mu, scale=sigma)
print(f" pdf({x:2d}) = {pdf:.4f}")Salida:
pdf(-2) = 0.0540
pdf(-1) = 0.2420
pdf( 0) = 0.3989
pdf( 1) = 0.2420
pdf( 2) = 0.0540La PDF es simétrica: pdf(-1) es igual a pdf(1), y pdf(0) es el máximo (el pico de la curva en campana). El valor de la PDF en sí no es una probabilidad — es una densidad. Para obtener una probabilidad, hay que integrar la PDF en un rango, que es lo que hace la CDF.
Función de Distribución Acumulada (CDF)
La CDF en un valor x da la probabilidad de que una observación extraída aleatoriamente sea menor o igual a x. Usa stats.norm.cdf() para responder preguntas prácticas de probabilidad:
from scipy import stats
mu, sigma = 170, 10 # adult heights in cm
# Probability that a randomly chosen person is shorter than 180 cm
p_below_180 = stats.norm.cdf(180, loc=mu, scale=sigma)
print(f"P(height < 180 cm) = {p_below_180:.4f}")
# Probability of being taller than 185 cm
p_above_185 = 1 - stats.norm.cdf(185, loc=mu, scale=sigma)
print(f"P(height > 185 cm) = {p_above_185:.4f}")
# Probability of falling between 160 cm and 180 cm
p_range = stats.norm.cdf(180, loc=mu, scale=sigma) - stats.norm.cdf(160, loc=mu, scale=sigma)
print(f"P(160 < height < 180 cm) = {p_range:.4f}")Salida:
P(height < 180 cm) = 0.8413
P(height > 185 cm) = 0.0668
P(160 < height < 180 cm) = 0.6827El tercer resultado confirma la regla empírica: el rango μ±σ (160–180 cm) contiene aproximadamente el 68% de las observaciones.
Puntuaciones Z: Estandarizar la Distribución
Una puntuación Z (también llamada puntuación estándar) mide cuántas desviaciones estándar se aleja un valor de la media:
Z = (x − μ) / σLas puntuaciones Z permiten comparar valores de distribuciones con diferentes medias y desviaciones estándar en una escala común. Una puntuación Z de +2.0 significa que un valor está dos desviaciones estándar por encima de la media, independientemente de las unidades originales.
import numpy as np
from scipy import stats
heights = np.array([171.3, 168.7, 176.4, 171.0, 164.6, 173.6, 183.0, 179.5])
# Calculate Z-scores manually
mean = heights.mean()
std = heights.std(ddof=1) # ddof=1 for the sample standard deviation
z_manual = (heights - mean) / std
print("Z-scores (manual):", np.round(z_manual, 2))
# Or use scipy directly
z_scipy = stats.zscore(heights, ddof=1)
print("Z-scores (scipy): ", np.round(z_scipy, 2))Salida:
Z-scores (manual): [-0.37 -0.81 0.49 -0.42 -1.5 0.01 1.59 1.01]
Z-scores (scipy): [-0.37 -0.81 0.49 -0.42 -1.5 0.01 1.59 1.01]Una persona con una altura de 183.0 cm tiene una puntuación Z de +1.59, lo que significa que está 1.59 desviaciones estándar por encima de la media. En una distribución normal, esto la sitúa aproximadamente en el 6% superior de la población.
Cuándo son útiles las puntuaciones Z
- Detección de valores atípicos: los valores con
|Z| > 3son casi con certeza valores atípicos en una distribución normal. - Escalado de características: convertir características a puntuaciones Z (media cero, varianza unitaria) se llama estandarización y es necesario para algoritmos sensibles a la magnitud de las características, como SVM y k-vecinos más cercanos. Consulta el capítulo de escalado de características para ver cómo aplicarlo con
StandardScalerde scikit-learn. - Comparar cosas dispares: si deseas comparar la puntuación de matemáticas de un estudiante (media 70, desviación 10) con su puntuación de lectura (media 50, desviación 5), las puntuaciones Z ofrecen una comparación justa.
Comprobar si los Datos Tienen Distribución Normal
Antes de aplicar algoritmos que asuman normalidad, verifica la suposición. Los dos enfoques más comunes son la prueba de Shapiro-Wilk (para muestras de hasta ~5 000) y una inspección visual rápida.
Prueba de Shapiro-Wilk
La prueba de Shapiro-Wilk devuelve un estadístico W y un valor p. Un valor p superior a 0.05 significa que no hay suficiente evidencia para rechazar la normalidad. Un valor p igual o inferior a 0.05 indica que los datos probablemente no son normales.
import numpy as np
from scipy import stats
rng = np.random.default_rng(seed=42)
# Normally distributed sample
normal_sample = rng.normal(loc=0, scale=1, size=50)
stat_n, p_n = stats.shapiro(normal_sample)
print(f"Normal sample — W={stat_n:.3f}, p={p_n:.3f}")
if p_n > 0.05:
print(" => Cannot reject normality.")
else:
print(" => Reject normality.")
# Skewed sample (exponential distribution)
skewed_sample = rng.exponential(scale=1, size=50)
stat_s, p_s = stats.shapiro(skewed_sample)
print(f"Skewed sample — W={stat_s:.3f}, p={p_s:.3f}")
if p_s > 0.05:
print(" => Cannot reject normality.")
else:
print(" => Reject normality.")Salida:
Normal sample — W=0.984, p=0.730
=> Cannot reject normality.
Skewed sample — W=0.808, p=0.000
=> Reject normality.La muestra normal supera la prueba con facilidad (p=0.730). La muestra con sesgo falla de forma decisiva (p≈0).
Cuándo importa la prueba de normalidad
No todos los algoritmos necesitan características con distribución normal. Los modelos basados en árboles (árboles de decisión, bosques aleatorios, gradient boosting) y las redes neuronales son completamente agnósticos respecto a la distribución. La normalidad importa más para:
- Pruebas estadísticas paramétricas (prueba t, ANOVA, correlación de Pearson) — los valores p de estas pruebas solo son válidos si los datos son aproximadamente normales.
- Análisis discriminante lineal (LDA) — asume que cada clase tiene distribución normal.
- Naive Bayes gaussiano — modela explícitamente cada característica como una distribución gaussiana.
- Intervalos de confianza e intervalos de predicción en regresión lineal — derivados de la normalidad de los residuos.
Cuando los Datos No Son Normales: Transformación Logarítmica
Un remedio habitual para los datos sesgados a la derecha (por ejemplo, ingresos, precios de viviendas, montos de transacciones) es la transformación logarítmica, que comprime los valores grandes y amplía los pequeños. El resultado suele aproximarse a la normalidad:
import numpy as np
from scipy import stats
rng = np.random.default_rng(seed=7)
# Simulate log-normally distributed incomes (a realistic pattern)
incomes = rng.lognormal(mean=10.5, sigma=0.5, size=1000)
log_incomes = np.log(incomes)
sk_before = stats.skew(incomes)
sk_after = stats.skew(log_incomes)
stat_before, p_before = stats.shapiro(incomes[:50])
stat_after, p_after = stats.shapiro(log_incomes[:50])
print(f"Before transform — skewness: {sk_before:.2f}, Shapiro p={p_before:.3f}")
print(f"After log transform — skewness: {sk_after:.2f}, Shapiro p={p_after:.3f}")Salida:
Before transform — skewness: 1.44, Shapiro p=0.000
After log transform — skewness: 0.01, Shapiro p=0.940Tras la transformación logarítmica, el sesgo cae de 1.44 a casi cero, y el valor p de Shapiro-Wilk sube de 0.000 a 0.940 — los datos transformados superan fácilmente la prueba de normalidad.
Consideraciones importantes:
- La transformación logarítmica requiere que todos los valores sean estrictamente positivos. Si los datos contienen ceros, usa
np.log(x + 1)(transformación log más uno). - Si los datos tienen un sesgo a la izquierda (cola larga hacia la izquierda), prueba una transformación cuadrada o de reflexión en su lugar.
- Aplica siempre la misma transformación tanto al conjunto de entrenamiento como a los nuevos datos en el momento de la inferencia.
Por Qué la Distribución Normal Importa en el Aprendizaje Automático
La distribución normal aparece en todas partes del aprendizaje automático, a menudo de forma implícita:
- Teorema del límite central: la media de una muestra aleatoria grande tiene distribución aproximadamente normal, independientemente de la distribución original. Esto sustenta los intervalos de confianza y las pruebas de hipótesis sobre métricas de modelos.
- Análisis de residuos: los residuos de una regresión lineal bien ajustada deben ser aproximadamente normales. Las desviaciones indican una mala especificación del modelo.
- Inicialización de pesos en redes neuronales: esquemas como la inicialización de Xavier y He extraen los pesos iniciales de distribuciones normales para evitar el desvanecimiento o la explosión de gradientes.
- Procesos gaussianos: una familia de modelos probabilísticos que colocan una distribución normal sobre funciones, utilizada en optimización bayesiana y cuantificación de incertidumbre.
- Detección de valores atípicos: en muchos dominios, los datos más allá de ±3σ de la media se marcan como anomalías.
Comprender dónde se asume la distribución normal — y cuándo esa suposición falla — ayuda a evitar errores silenciosos en el modelado.
Resumen
- La distribución normal está definida por su media (μ) y desviación estándar (σ); su curva en forma de campana es simétrica alrededor de la media.
- La regla empírica establece que el 68%, el 95% y el 99.7% de los valores se encuentran dentro de 1, 2 y 3 desviaciones estándar de la media.
- Usa
numpy.random.default_rng().normal()para generar muestras con distribución normal yscipy.stats.norm.pdf()/.cdf()para evaluar probabilidades. - Las puntuaciones Z estandarizan los valores a una escala común; son esenciales para la detección de valores atípicos y el escalado de características.
- Usa
scipy.stats.shapiro()para probar formalmente la normalidad — pero recuerda que muchos algoritmos modernos de aprendizaje automático no la requieren. - Cuando los datos tienen sesgo a la derecha, una transformación logarítmica a menudo los hace aproximadamente normales.
Para una comparación más amplia de tipos de distribución (uniforme, sesgada, multimodal), consulta el capítulo Distribución de Datos. Para saber cómo medir la dispersión y el centro, consulta Desviación Estándar y Media, Mediana y Moda.