La lección anterior terminó con una pregunta incómoda: la correlación de 0,35 entre inactividad y churn, ¿es real o es un espejismo de la muestra? La inferencia estadística es la disciplina que responde a ese tipo de preguntas: cómo pasar de lo que vemos en una muestra a afirmaciones fiables sobre la población (distinción que definimos en 02-01), cuantificando la incertidumbre en cada paso. En esta lección aprenderás a estimar con intervalos de confianza, entenderás el teorema central del límite mediante simulación, y realizarás contrastes de hipótesis (t-test y chi-cuadrado) con scipy, aplicándolos al test A/B de la nueva página de MercaFresh. Estas herramientas te acompañarán en todo el curso: comparar dos modelos de ML es, en el fondo, comparar dos muestras de resultados.
Contenido
- Estimación puntual y por intervalos
- El teorema central del límite (con simulación)
- Contrastes de hipótesis: la lógica
- p-valor y errores tipo I y II
- El t-test en la práctica: test A/B de MercaFresh
- El test chi-cuadrado para variables categóricas
- Conexión con Machine Learning
Estimación puntual y por intervalos
Una estimación puntual resume un parámetro poblacional con un único número calculado de la muestra: "el gasto medio por pedido es 47,20 €". Es útil pero engañosamente precisa: otra muestra habría dado 46,80 o 47,90.
Una estimación por intervalo añade la incertidumbre: "el gasto medio está entre 45,90 y 48,50 € con un 95 % de confianza". Ese rango es el intervalo de confianza (IC).
La pieza clave es el error estándar (SE): la desviación estándar del estimador, no de los datos. Para la media muestral:
SE = s / √n
donde s es la desviación estándar muestral y n el tamaño de la muestra. Fíjate en el √n: para reducir el error a la mitad hacen falta cuatro veces más datos. El IC al 95 % para la media (con n razonablemente grande) es aproximadamente:
x̄ ± 1,96 · SE
import numpy as np
from scipy import stats
rng = np.random.default_rng(42)
# Muestra: importes de 400 pedidos de MercaFresh
importes = rng.gamma(shape=4.0, scale=12.0, size=400)
media = importes.mean()
se = importes.std(ddof=1) / np.sqrt(len(importes))
# IC al 95% usando la distribución t de Student (correcta para cualquier n)
ic = stats.t.interval(0.95, df=len(importes) - 1, loc=media, scale=se)
print(f"Media muestral: {media:.2f} EUR")
print(f"IC 95%: ({ic[0]:.2f}, {ic[1]:.2f}) EUR")Salida aproximada:
std(ddof=1)fuerza la desviación muestral (n−1) porqueimporteses un array de NumPy (recuerda la diferencia de defaults vista en 02-01).stats.t.intervalusa la distribución t de Student, una campana con colas algo más pesadas que la normal que corrige la incertidumbre extra de estimar s; con n = 400 es casi idéntica a usar ±1,96.
Interpretación correcta del 95 %: si repitiéramos el muestreo muchas veces y calculáramos un IC cada vez, el 95 % de esos intervalos contendría la verdadera media poblacional. No es exactamente "hay un 95 % de probabilidad de que μ esté en este intervalo" (μ es fija; lo aleatorio es el intervalo), aunque en la práctica se lea así de forma informal.
El teorema central del límite (con simulación)
¿Por qué podemos usar campanas (normal o t) para la media, si los importes de MercaFresh son asimétricos con cola derecha? Por el resultado más importante de la estadística:
Teorema central del límite (TCL): la distribución de la media de n observaciones independientes se aproxima a una normal cuando n crece, sea cual sea la distribución original de los datos (mientras tenga varianza finita). Su centro es μ y su desviación es σ/√n.
En lugar de demostrarlo, veámoslo:
import matplotlib.pyplot as plt
rng = np.random.default_rng(0)
# Población MUY asimétrica: importes exponenciales con media 40 EUR
poblacion = lambda size: rng.exponential(scale=40, size=size)
fig, axes = plt.subplots(1, 4, figsize=(14, 3.2), sharey=False)
# Panel 0: la distribución original (nada de campana)
axes[0].hist(poblacion(10_000), bins=60, color="gray")
axes[0].set_title("Datos originales\n(exponencial)")
# Paneles 1-3: distribución de la MEDIA de muestras de tamaño n
for ax, n in zip(axes[1:], [5, 30, 200]):
medias = np.array([poblacion(n).mean() for _ in range(5_000)])
ax.hist(medias, bins=60, color="steelblue")
ax.set_title(f"Medias de muestras\nn = {n}")
plt.tight_layout()
plt.show()Qué hace el código: extrae 5.000 muestras de tamaño n de una población exponencial (asimétrica total) y dibuja el histograma de sus 5.000 medias. El resultado:
- Con n = 5, el histograma de medias aún hereda asimetría.
- Con n = 30, ya es una campana bastante decente.
- Con n = 200, es una normal de libro, mucho más estrecha (efecto σ/√n).
Este es el fundamento que legitima los intervalos de confianza y los tests de esta lección incluso con datos no normales, siempre que n no sea minúsculo. También explica el papel estelar de la distribución normal anunciado en 02-02.
Contrastes de hipótesis: la lógica
Un contraste de hipótesis es un procedimiento para decidir, con reglas explícitas, si los datos aportan evidencia suficiente contra una afirmación por defecto.
- Hipótesis nula (H₀): la afirmación "aburrida", de no-efecto. "La nueva página de producto no cambia el gasto medio."
- Hipótesis alternativa (H₁): lo que sospechamos. "La nueva página cambia el gasto medio."
La lógica es análoga a un juicio: H₀ es inocente hasta que se demuestre lo contrario. Calculamos qué tan raros serían nuestros datos si H₀ fuera cierta; si son suficientemente raros, rechazamos H₀.
graph TD
A["Formular H0 y H1"] --> B["Elegir test y nivel alfa (p.ej. 0.05)"]
B --> C["Recoger datos y calcular estadistico"]
C --> D["Calcular p-valor"]
D --> E{"p-valor < alfa?"}
E -- "Si" --> F["Rechazar H0:<br>efecto estadisticamente significativo"]
E -- "No" --> G["No rechazar H0:<br>evidencia insuficiente"]
Importante: "no rechazar H₀" no es "demostrar H₀". La ausencia de evidencia no es evidencia de ausencia; quizá el efecto existe pero la muestra es pequeña.
p-valor y errores tipo I y II
El p-valor es la probabilidad de observar datos tan extremos como los nuestros (o más) suponiendo que H₀ es cierta. Un p-valor de 0,03 significa: "si la nueva página no tuviera efecto alguno, solo en un 3 % de los experimentos veríamos una diferencia como esta por puro azar".
Lo que el p-valor no es:
- No es la probabilidad de que H₀ sea cierta.
- No mide el tamaño del efecto: con n gigante, una diferencia irrisoria de 0,02 € puede dar p < 0,001.
El umbral α (típicamente 0,05) fija cuánto riesgo de falsa alarma aceptamos, y de ahí salen los dos errores posibles:
| H₀ es cierta (no hay efecto) | H₀ es falsa (hay efecto) | |
|---|---|---|
| Rechazamos H₀ | Error tipo I (falsa alarma), prob. α | Acierto (potencia del test) |
| No rechazamos H₀ | Acierto | Error tipo II (efecto no detectado), prob. β |
En MercaFresh: un error tipo I sería rediseñar toda la web por una mejora que no existía; un error tipo II, descartar una página que realmente vendía más. Bajar α reduce las falsas alarmas pero aumenta los efectos perdidos: es un compromiso, no una verdad revelada. (Esta misma tensión reaparecerá en el módulo 6 como el equilibrio entre falsos positivos y falsos negativos de un clasificador.)
El t-test en la práctica: test A/B de MercaFresh
Caso: MercaFresh lanza una nueva página de producto y quiere saber si mejoró el gasto medio por pedido. Durante dos semanas, la mitad de los visitantes ve la página antigua (grupo A, control) y la otra mitad la nueva (grupo B, tratamiento), asignados al azar. La asignación aleatoria es la clave que permite hablar de causalidad, cerrando el círculo de "correlación no es causalidad" de 02-03.
El t-test de dos muestras independientes contrasta H₀: "las medias de ambos grupos son iguales".
rng = np.random.default_rng(7)
# Simulamos el experimento: la pagina nueva sube el gasto medio ~2 EUR
grupo_A = rng.gamma(shape=4.0, scale=12.0, size=980) # media ~48 EUR
grupo_B = rng.gamma(shape=4.0, scale=12.5, size=1020) # media ~50 EUR
print(f"Media A: {grupo_A.mean():.2f} | Media B: {grupo_B.mean():.2f}")
print(f"Diferencia observada: {grupo_B.mean() - grupo_A.mean():.2f} EUR")
# t-test de Welch (equal_var=False): no asume varianzas iguales
t_stat, p_valor = stats.ttest_ind(grupo_B, grupo_A, equal_var=False)
print(f"t = {t_stat:.2f}, p-valor = {p_valor:.4f}")Salida aproximada:
Interpretación paso a paso:
- La diferencia observada es de unos 2,50 € por pedido a favor de la nueva página.
- El p-valor ≈ 0,02 < 0,05: si la página nueva no tuviera efecto, una diferencia así solo aparecería en ~2 % de los experimentos. Rechazamos H₀: la mejora es estadísticamente significativa.
- Decisión de negocio: significativa y relevante (2,50 € × miles de pedidos/mes justifica el cambio). Comprueba siempre ambas cosas: significación estadística y tamaño del efecto.
Notas técnicas:
stats.ttest_indimplementa el t-test para muestras independientes;equal_var=False(test de Welch) es la opción segura por defecto porque no exige varianzas iguales entre grupos.- ¿Datos asimétricos como estos? El TCL nos protege: con ~1.000 observaciones por grupo, las medias se comportan como normales.
- Existe también
stats.ttest_relpara muestras pareadas (el mismo cliente medido antes y después) ystats.ttest_1samppara comparar una muestra contra un valor fijo ("¿el tiempo medio de entrega supera los 40 min prometidos?").
El test chi-cuadrado para variables categóricas
El t-test compara medias de variables numéricas. Cuando ambas variables son categóricas, el test adecuado es el chi-cuadrado de independencia: contrasta H₀: "las dos variables son independientes" a partir de su tabla de contingencia.
Caso MercaFresh: ¿la tasa de conversión (comprar o no) depende de la versión de la página?
import pandas as pd
# Tabla de contingencia observada del test A/B
# compra no_compra
tabla = pd.DataFrame({"compra": [312, 368],
"no_compra": [2688, 2632]},
index=["pagina_A", "pagina_B"])
print(tabla)
print(f"Conversion A: {312/3000:.1%} | Conversion B: {368/3000:.1%}")
chi2, p_valor, gl, esperados = stats.chi2_contingency(tabla)
print(f"chi2 = {chi2:.2f}, p-valor = {p_valor:.4f}, grados de libertad = {gl}")Salida:
compra no_compra
pagina_A 312 2688
pagina_B 368 2632
Conversion A: 10.4% | Conversion B: 12.3%
chi2 = 5.15, p-valor = 0.0232, grados de libertad = 1Cómo funciona por dentro (intuición): el test calcula qué tabla esperaríamos si hubiera independencia (mismas proporciones en ambas filas: esperados la devuelve) y mide cuánto se desvían los conteos observados de los esperados. Desviación grande → chi² grande → p-valor pequeño.
Aquí p ≈ 0,023 < 0,05: la conversión sí depende de la página; la versión B convierte significativamente más (12,3 % vs. 10,4 %). El chi-cuadrado también sirve para preguntas como "¿el método de pago depende de la provincia?" o "¿el churn depende del nivel de fidelidad?".
| Pregunta | Variables | Test |
|---|---|---|
| ¿Difiere el gasto medio entre dos grupos? | Numérica vs. binaria | t-test de dos muestras |
| ¿Cambió la media tras una intervención (mismos sujetos)? | Numérica, pareada | t-test pareado |
| ¿La media supera un valor de referencia? | Numérica vs. constante | t-test de una muestra |
| ¿Dos categóricas son independientes? | Categórica vs. categórica | Chi-cuadrado |
Conexión con Machine Learning
La inferencia impregna la práctica del ML más de lo que parece:
- Comparar modelos. "El modelo nuevo acierta el 84,1 % y el viejo el 83,6 %": ¿mejora real o ruido de la muestra de evaluación? La diferencia entre dos accuracies es una diferencia entre dos proporciones muestrales, exactamente el terreno de esta lección. En el módulo 6 veremos cómo la validación cruzada (06-03) genera varias mediciones por modelo, lo que permite razonar sobre la variabilidad del rendimiento en lugar de fiarse de un único número.
- Tests A/B de modelos en producción. Desplegar el modelo nuevo para el 50 % del tráfico y comparar métricas de negocio es literalmente el experimento de esta lección; lo retomaremos en el módulo 8.
- Escepticismo cuantificado. El hábito mental del p-valor —"¿podría esto ser azar?"— es la mejor vacuna contra conclusiones precipitadas al explorar datos, incluidas las correlaciones "prometedoras" de la lección anterior.
Errores Comunes y Consejos
- Interpretar el p-valor como P(H₀ cierta). Es P(datos así de extremos | H₀ cierta): condiciona en la dirección contraria. Esta distinción conecta directamente con la próxima lección (Bayes).
- Confundir significación con relevancia. Con n enorme, todo es "significativo". Reporta siempre el tamaño del efecto (la diferencia en euros, en puntos de conversión) junto al p-valor.
- Mirar los resultados cada día y parar el test cuando p < 0,05. Este "peeking" infla drásticamente los falsos positivos: fija la duración o el tamaño muestral antes de empezar.
- Hacer muchos tests y quedarse con los que salen. Con 20 tests a α = 0,05, lo esperable es ~1 falso positivo. Si haces comparaciones múltiples, ajústalo (p. ej., corrección de Bonferroni: usar α/20) o al menos decláralo.
- Usar el t-test con muestras minúsculas y muy asimétricas. El TCL necesita n suficiente; con n < 20-30 y colas fuertes, desconfía (existen tests no paramétricos como Mann-Whitney,
stats.mannwhitneyu, como alternativa). - Olvidar la asignación aleatoria en un A/B. Si el grupo B son "los usuarios de la app nueva", ya no comparas páginas, comparas tipos de usuario: el confusor de 02-03 en acción.
- Consejo: antes de lanzar un experimento, escribe H₀, H₁, α y el tamaño de muestra en un documento. Los experimentos definidos a posteriori encuentran lo que quieren encontrar.
Ejercicios
Ejercicio 1
Con una muestra de 100 tiempos de entrega de MercaFresh (media muestral 41,3 min, desviación estándar muestral 9,8 min), calcula a mano el error estándar y un IC del 95 % aproximado para la media (usa ±1,96·SE). MercaFresh promete "entrega media por debajo de 40 min": ¿el intervalo es compatible con esa promesa?
Ejercicio 2
Simula con NumPy el TCL para una distribución uniforme entre 0 y 10: dibuja el histograma de las medias de 5.000 muestras de tamaño n = 2 y n = 50. ¿Qué observas en la forma y en la anchura? ¿Qué anchura teórica predice el TCL para n = 50? (σ de una uniforme(0,10) ≈ 2,89).
Ejercicio 3
MercaFresh prueba dos asuntos de email para reactivar clientes inactivos. Asunto A: 1.500 envíos, 129 reactivaciones. Asunto B: 1.500 envíos, 168 reactivaciones. Plantea H₀ y H₁, construye la tabla de contingencia, ejecuta el chi-cuadrado con scipy y concluye con α = 0,05.
Soluciones
Solución 1
- SE = 9,8 / √100 = 0,98 min.
- IC 95 % ≈ 41,3 ± 1,96 · 0,98 = 41,3 ± 1,92 → (39,4, 43,2) minutos.
- El intervalo contiene valores por debajo de 40, así que no podemos descartar que la media real cumpla la promesa... pero la mayor parte del intervalo está por encima de 40 y la estimación puntual también. Formalmente: un t-test de una muestra contra 40 no rechazaría H₀ al 5 % (la evidencia de incumplimiento no es concluyente), aunque operativamente MercaFresh haría bien en vigilar el reparto.
Solución 2
import numpy as np, matplotlib.pyplot as plt
rng = np.random.default_rng(3)
fig, axes = plt.subplots(1, 2, figsize=(9, 3))
for ax, n in zip(axes, [2, 50]):
medias = rng.uniform(0, 10, size=(5_000, n)).mean(axis=1)
ax.hist(medias, bins=50, color="steelblue")
ax.set_title(f"n = {n} (std = {medias.std():.2f})")
plt.tight_layout(); plt.show()Con n = 2 la distribución de medias es triangular (aún no normal); con n = 50 es una campana clara y mucho más estrecha. El TCL predice desviación σ/√n = 2,89/√50 ≈ 0,41, que coincidirá con la std empírica del panel derecho. Truco del código: generar una matriz 5.000×n y promediar por filas (mean(axis=1)) evita el bucle.
Solución 3
- H₀: la tasa de reactivación es independiente del asunto (misma tasa en A y B). H₁: las tasas difieren.
import pandas as pd
from scipy import stats
tabla = pd.DataFrame({"reactiva": [129, 168],
"no_reactiva": [1371, 1332]},
index=["asunto_A", "asunto_B"])
chi2, p, gl, esp = stats.chi2_contingency(tabla)
print(f"Tasa A: {129/1500:.1%} | Tasa B: {168/1500:.1%}")
print(f"chi2 = {chi2:.2f}, p = {p:.4f}")Resultado: tasas del 8,6 % vs. 11,2 %, chi² ≈ 5,4, p ≈ 0,020 < 0,05. Rechazamos H₀: el asunto B reactiva significativamente más clientes. Con un tamaño de efecto de +2,6 puntos porcentuales sobre 1.500 envíos, además de significativo es accionable: MercaFresh debería adoptar el asunto B (idealmente confirmándolo sin "peeking" en una segunda oleada).
Conclusión
Has recorrido el núcleo de la inferencia estadística: estimar con intervalos de confianza en lugar de números secos, entender por qué el teorema central del límite hace que las medias se comporten como normales, y ejecutar contrastes de hipótesis completos —t-test para medias y chi-cuadrado para categóricas— interpretando p-valores y vigilando los errores tipo I y II. El test A/B de MercaFresh mostró el circuito completo, de la hipótesis a la decisión de negocio, y dejaste anotada la conexión con ML: comparar modelos es comparar muestras. Pero la inferencia clásica deja una pregunta sin responder de frente: ¿cómo actualizar lo que ya creíamos al recibir evidencia nueva? Esa es exactamente la especialidad del teorema de Bayes, con el que cerraremos el módulo en la próxima lección.
Curso de Machine Learning
Módulo 1: Introducción al Machine Learning
- ¿Qué es el Machine Learning?
- Historia y evolución del Machine Learning
- Tipos de Machine Learning
- Aplicaciones del Machine Learning
- El flujo de trabajo de un proyecto de Machine Learning
Módulo 2: Fundamentos de Estadística y Probabilidad
- Conceptos básicos de estadística
- Distribuciones de probabilidad
- Correlación y covarianza
- Inferencia estadística
- Teorema de Bayes
Módulo 3: Preprocesamiento de Datos
- Limpieza de datos
- Manejo de datos faltantes
- Transformación de datos
- Codificación de variables categóricas
- Normalización y estandarización
- Ingeniería de características
Módulo 4: Algoritmos de Machine Learning Supervisado
- Regresión lineal
- Regresión logística
- Árboles de decisión
- Máquinas de soporte vectorial (SVM)
- K-Vecinos más cercanos (K-NN)
- Naive Bayes
- Redes neuronales
Módulo 5: Algoritmos de Machine Learning No Supervisado
- Clustering: K-means
- Clustering jerárquico
- Análisis de componentes principales (PCA)
- Análisis de agrupamiento DBSCAN
- Visualización de datos con t-SNE y UMAP
Módulo 6: Evaluación y Validación de Modelos
- División de datos: entrenamiento, validación y prueba
- Métricas de evaluación
- Validación cruzada
- Curva ROC y AUC
- Overfitting y underfitting
Módulo 7: Técnicas Avanzadas y Optimización
- Regularización: Ridge, Lasso y Elastic Net
- Ensemble Learning
- Gradient Boosting
- Redes neuronales profundas (Deep Learning)
- Optimización de hiperparámetros
Módulo 8: Implementación y Despliegue de Modelos
- Frameworks y bibliotecas populares
- Implementación de modelos en producción
- Mantenimiento y monitoreo de modelos
- Consideraciones éticas y de privacidad
Módulo 9: Proyectos Prácticos
- Proyecto 1: Predicción de precios de viviendas
- Proyecto 2: Clasificación de imágenes
- Proyecto 3: Análisis de sentimientos en redes sociales
- Proyecto 4: Detección de fraudes
- Proyecto 5: Segmentación de clientes
