Distribución de Datos en Machine Learning
Aprende cómo funcionan las distribuciones de datos en Python: normal, sesgada y uniforme, cómo detectarlas y por qué importan en modelos.
La distribución de datos describe cómo se dispersan los valores en un conjunto de datos — qué valores son comunes, cuáles son raros y hasta qué distancia se extienden desde el centro. Antes de entrenar cualquier modelo de machine learning, comprender la distribución de tus datos te ayuda a elegir el algoritmo correcto, detectar anomalías, decidir si escalar o transformar las características y evitar sesgos ocultos en las predicciones.
Este capítulo cubre las formas de distribución más comunes, cómo medirlas en Python usando NumPy y SciPy, y qué significa cada distribución para tus decisiones de modelado.
¿Qué Es la Distribución de Datos?
Una distribución de datos es el patrón de con qué frecuencia aparece cada valor (o rango de valores) en un conjunto de datos. Cuando graficas una distribución, generalmente ves una curva o histograma cuya forma te dice mucho sobre los datos subyacentes.
Las tres propiedades que definen cualquier distribución son:
- Centro — donde se agrupan la mayoría de los valores (medido por media, mediana y moda)
- Dispersión — qué tan lejos se desvían los valores del centro (medido por la desviación estándar y el rango intercuartílico)
- Forma — si la distribución es simétrica, sesgada o plana
Comprender las tres es necesario antes de ingresar datos a un modelo.
Tipos de Distribución Comunes
Distribución Normal
La distribución normal (también llamada distribución gaussiana) es la distribución más importante en estadística y machine learning. Su histograma forma una curva de campana simétrica: los valores se agrupan alrededor de la media y la frecuencia cae igualmente en ambos lados.
Propiedades clave:
- La media, la mediana y la moda son todas iguales.
- Aproximadamente el 68% de los valores caen dentro de una desviación estándar de la media, el 95% dentro de dos y el 99,7% dentro de tres (la regla empírica).
- Definida completamente por dos parámetros: media (μ) y desviación estándar (σ).
Muchos fenómenos del mundo real se aproximan a una distribución normal — las alturas humanas, los errores de medición y las puntuaciones de CI son ejemplos clásicos. Algoritmos como el análisis discriminante lineal, Gaussian naive Bayes y la regresión lineal asumen (o se benefician de) características distribuidas 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%)Distribución Sesgada
Una distribución sesgada es asimétrica: una cola es más larga que la otra. El sesgo se mide mediante el estadístico de asimetría — los valores positivos indican un sesgo a la derecha (positivo), los valores negativos indican un sesgo a la izquierda (negativo) y los valores cercanos a cero indican aproximada simetría.
Sesgada positivamente (hacia la derecha): la cola se extiende hacia la derecha. La media es arrastrada por encima de la mediana por un pequeño número de valores muy grandes. Los ingresos y los precios de las casas son ejemplos típicos — un puñado de personas con ingresos muy altos o propiedades costosas arrastra la media muy por encima de la mediana.
Sesgada negativamente (hacia la izquierda): la cola se extiende hacia la izquierda. Las puntuaciones de exámenes fáciles a menudo muestran este patrón — la mayoría de los estudiantes puntúan cerca de la cima, pero unos pocos puntúan muy bajo.
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 skewOutput:
--- Salary distribution ---
Mean: 59769
Median: 40000
Skewness: 2.16
--- Exam score distribution ---
Mean: 82.8
Median: 88.0
Skewness: -1.77Cuando hay sesgo, la media es una medida engañosa del centro. La mediana suele ser un estadístico de resumen mejor para datos sesgados.
Distribución Uniforme
En una distribución uniforme, todos los valores (o rangos de valores) tienen la misma probabilidad. Un dado justo de seis caras produce una distribución discreta uniforme; elegir aleatoriamente un número flotante entre 0 y 1 produce una distribución continua uniforme.
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.000Las distribuciones uniformes aparecen en el muestreo aleatorio, la aumentación de datos y como distribuciones a priori en modelos bayesianos.
Resumir una Distribución en Python
Antes de modelar, calcula siempre un resumen rápido de cada característica. NumPy y SciPy juntos cubren las estadísticas clave:
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 = symmetricOutput:
--- Distribution Summary ---
Mean: 13.8
Median: 14.0
Std: 2.25
Min: 10
Max: 18
Skewness: 0.200Un sesgo cercano a 0.200 indica que los datos son aproximadamente simétricos — sin sesgo pronunciado en ninguna dirección.
Prueba de Normalidad
Algunos algoritmos asumen explícitamente que las características están distribuidas normalmente. La prueba de Shapiro-Wilk es la prueba más confiable para muestras pequeñas (n < 5 000). Devuelve un estadístico W y un valor p. Un valor p mayor a 0.05 significa que no puedes rechazar la hipótesis de que los datos son normales.
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.Cuándo usarla: aplica la prueba de Shapiro-Wilk cuando las suposiciones de un modelo requieren explícitamente normalidad — por ejemplo, antes de usar una prueba t paramétrica o análisis discriminante lineal. Muchos algoritmos modernos (gradient boosting, random forests, redes neuronales) no son sensibles a la forma de distribución de las características, por lo que no siempre necesitas esta prueba.
Por Qué la Forma de la Distribución Importa en el Modelado
| Situación | Qué significa | Qué hacer |
|---|---|---|
| Características normales | Las suposiciones estándar se cumplen | Usar modelos paramétricos tal cual |
| Características sesgadas a la derecha | La media está inflada; los valores atípicos dominan | Aplicar transformación logarítmica o de raíz cuadrada |
| Características sesgadas a la izquierda | Los valores bajos son valores atípicos | Aplicar transformación cuadrática o de reflexión |
| Características uniformes | Sin agrupamiento central | Generalmente bien; normalizar para modelos basados en distancia |
| Características multimodales | Múltiples clústeres | Considerar dividir los datos o usar un paso de agrupamiento |
Manejo de Datos Sesgados con Transformación Logarítmica
Un remedio común para los datos sesgados a la derecha es la transformación logarítmica, que comprime los valores grandes y expande los pequeños, produciendo frecuentemente una distribución más cercana a la normal.
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.01Después de la transformación logarítmica, el sesgo baja de 1.44 a casi cero, haciendo que los datos sean mucho más adecuados para modelos que asumen normalidad.
Nota: la transformación logarítmica requiere que todos los valores sean estrictamente positivos. Agrega una pequeña constante (p. ej., np.log(x + 1)) si tus datos contienen ceros.
Visualización de la Distribución de Datos
La visualización es la forma más rápida de inspeccionar una distribución. Un histograma divide los valores en intervalos y muestra cuántas observaciones caen en cada intervalo. Usa histogramas de Matplotlib para crearlos:
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()Para una visión general más rápida de múltiples características a la vez, usa un diagrama de dispersión para buscar relaciones entre distribuciones.
Distribución y Escalado de Características
Si tus características tienen distribuciones o escalas muy diferentes, los algoritmos basados en distancia (k-vecinos más cercanos, SVM, k-means clustering) estarán dominados por las características con el rango más grande. El escalado de características es la solución estándar: StandardScaler normaliza cada característica a una media de 0 y desviación estándar de 1, y MinMaxScaler comprime los valores en [0, 1].
Elige el escalador según la distribución subyacente:
- Distribución normal →
StandardScaler(elimina la media, escala a varianza unitaria) - Distribución uniforme o acotada →
MinMaxScaler(preserva la forma) - Fuertemente sesgada con valores atípicos →
RobustScaler(usa la mediana y el IQR, ignorando los valores extremos)
Resumen
- Distribución normal: curva de campana simétrica; media ≈ mediana; adecuada para modelos paramétricos.
- Distribución sesgada: asimétrica; la media es arrastrada hacia la cola; las transformaciones logarítmicas o de potencia pueden reducir el sesgo.
- Distribución uniforme: todos los valores igualmente probables; aparece en el muestreo aleatorio y como distribuciones a priori no informativas.
- Usa
scipy.stats.skew()para medir la asimetría yscipy.stats.shapiro()para probar formalmente la normalidad. - Inspecciona siempre las distribuciones antes de modelar — la forma influye en qué algoritmo elegir, cómo transformar las características y qué estrategia de escalado aplicar.
A continuación, explora Distribución de Datos Normal para profundizar en la distribución gaussiana y cómo generarla y trabajar con ella usando SciPy.