En las dos lecciones anteriores analizamos cada variable de MercaFresh por separado: su forma, su centro, su dispersión. Pero las preguntas interesantes de negocio son casi siempre sobre relaciones: ¿los clientes que más tardan en recibir sus pedidos se dan de baja más? ¿Los pedidos grandes usan más el pago con tarjeta? La covarianza y la correlación son las herramientas que cuantifican si dos variables se mueven juntas, en qué dirección y con qué fuerza. Dominarlas es clave en Machine Learning: guían la selección de variables, avisan de redundancias y son el primer radar para encontrar señales de churn. También aprenderás su límite más importante: correlación no implica causalidad.

Contenido

  1. Covarianza: la idea y su limitación
  2. Correlación de Pearson: interpretación y rangos
  3. Correlación de Spearman: cuándo usarla
  4. Matrices de correlación y heatmaps con pandas
  5. Correlación no implica causalidad
  6. Relevancia para Machine Learning
  7. Caso MercaFresh: ¿qué variables se relacionan con el churn?

Covarianza: la idea y su limitación

La covarianza entre dos variables X e Y mide si tienden a desviarse de sus medias en la misma dirección:

cov(X, Y) = Σ (xᵢ − x̄)(yᵢ − ȳ) / (n − 1)

La intuición del producto (xᵢ − x̄)(yᵢ − ȳ):

  • Si cuando X está por encima de su media, Y también lo está (y viceversa), los productos son positivos → covarianza positiva.
  • Si cuando X sube, Y tiende a bajar, los productos son negativos → covarianza negativa.
  • Si no hay patrón, positivos y negativos se cancelan → covarianza cercana a 0.
import numpy as np
import pandas as pd

rng = np.random.default_rng(42)
n = 500

# Datos ficticios de 500 clientes de MercaFresh
n_articulos = rng.poisson(lam=14, size=n)                     # artículos por pedido
importe = 3.2 * n_articulos + rng.normal(0, 8, size=n)        # más artículos -> más euros
minutos_entrega = rng.gamma(9, 4.5, size=n)                   # independiente de lo anterior

df = pd.DataFrame({"n_articulos": n_articulos,
                   "importe": importe.round(2),
                   "minutos_entrega": minutos_entrega.round(1)})

print(df["n_articulos"].cov(df["importe"]).round(2))        # ~44 (positiva)
print(df["n_articulos"].cov(df["minutos_entrega"]).round(2)) # ~0-2 (cercana a 0)
  • Generamos el importe como 3,2 € por artículo más un ruido normal: hay relación real por construcción.
  • .cov() de pandas calcula la covarianza muestral (divide entre n−1, coherente con lo visto en 02-01).

La limitación de escala. La covarianza entre artículos e importe sale ≈ 44... ¿44 qué? Sus unidades son "artículos × euros". Si expresáramos el importe en céntimos, la covarianza se multiplicaría por 100 sin que la relación cambiara en absoluto. La magnitud de la covarianza no es interpretable por sí sola: solo su signo lo es. Necesitamos una versión sin unidades: la correlación.

Correlación de Pearson: interpretación y rangos

La correlación de Pearson normaliza la covarianza dividiéndola por el producto de las desviaciones estándar:

r = cov(X, Y) / (sₓ · s_y)

El resultado es un número sin unidades, siempre entre −1 y +1, invariante a cambios de escala:

  • r = +1: relación lineal positiva perfecta (todos los puntos en una recta ascendente).
  • r = −1: relación lineal negativa perfecta.
  • r = 0: ausencia de relación lineal (puede haber otra clase de relación).

| |r| aproximado | Interpretación habitual | |---|---| | 0,0 – 0,2 | Muy débil o nula | | 0,2 – 0,4 | Débil | | 0,4 – 0,6 | Moderada | | 0,6 – 0,8 | Fuerte | | 0,8 – 1,0 | Muy fuerte |

(Los umbrales son orientativos y dependen del dominio: en marketing un r = 0,3 puede ser oro; en un sensor físico, decepcionante.)

print(df["n_articulos"].corr(df["importe"]).round(3))          # ~0.85 (muy fuerte)
print(df["n_articulos"].corr(df["minutos_entrega"]).round(3))  # ~0.0

Dos advertencias fundamentales sobre Pearson:

  1. Solo detecta relaciones lineales. Una relación en forma de U perfecta (por ejemplo, gasto vs. edad, con máximo en la mediana edad) puede dar r ≈ 0.
  2. Es sensible a outliers. Un único pedido de hostelería de 900 € puede inflar o hundir la correlación. Recuerda el boxplot de la lección 02-01: inspecciona antes de calcular.

Por eso el mantra: dibuja siempre el scatter plot (plt.scatter(x, y) o df.plot.scatter(...)) antes de fiarte de un coeficiente.

Correlación de Spearman: cuándo usarla

La correlación de Spearman aplica la fórmula de Pearson a los rangos de los datos (la posición de cada valor una vez ordenados) en lugar de a los valores brutos. Mide si la relación es monótona (cuando X crece, Y crece —o decrece— consistentemente), aunque no sea lineal.

Úsala cuando:

  • La relación parece monótona pero curva (p. ej., el gasto crece con la antigüedad, pero saturándose).
  • Hay outliers fuertes: los rangos los domestican (el pedido de 900 € pasa a ser simplemente "el primero").
  • Alguna variable es ordinal (satisfacción baja/media/alta): Pearson no está justificado, Spearman sí.
# Relación monótona pero NO lineal: gasto ~ raíz de la antigüedad
antiguedad = rng.uniform(1, 60, size=n)                       # meses como cliente
gasto_mensual = 20 * np.sqrt(antiguedad) + rng.normal(0, 6, size=n)
s = pd.DataFrame({"antiguedad": antiguedad, "gasto": gasto_mensual})

print(s["antiguedad"].corr(s["gasto"], method="pearson").round(3))   # ~0.93
print(s["antiguedad"].corr(s["gasto"], method="spearman").round(3))  # ~0.95

Con una curva suave ambas son altas, pero Spearman captura mejor la monotonía; con outliers o curvas más agresivas, la diferencia entre ambas se agranda, y esa discrepancia es en sí misma un diagnóstico: si Spearman ≫ Pearson, sospecha de no linealidad u outliers.

Criterio Pearson Spearman
Qué mide Relación lineal Relación monótona
Datos requeridos Numéricos Numéricos u ordinales
Sensibilidad a outliers Alta Baja
Relación curva monótona La infravalora La captura

Matrices de correlación y heatmaps con pandas

Con muchas variables, calcular correlaciones por parejas a mano es inviable. La matriz de correlación las calcula todas de golpe:

import matplotlib.pyplot as plt

# Dataset de clientes de MercaFresh con variables candidatas para el churn
clientes = pd.DataFrame({
    "pedidos_mes": rng.poisson(6, n),
    "gasto_medio": rng.gamma(4, 12, n).round(2),
    "dias_desde_ultimo_pedido": rng.exponential(9, n).round(0),
    "incidencias_entrega": rng.poisson(0.7, n),
    "minutos_entrega_medio": minutos_entrega,
})
# Introducimos relaciones realistas a mano:
clientes["dias_desde_ultimo_pedido"] += 30 / (clientes["pedidos_mes"] + 1)
clientes["incidencias_entrega"] += (clientes["minutos_entrega_medio"] > 55).astype(int)

matriz = clientes.corr(method="pearson").round(2)
print(matriz)

# Heatmap con matplotlib puro
fig, ax = plt.subplots(figsize=(7, 6))
im = ax.imshow(matriz, cmap="coolwarm", vmin=-1, vmax=1)
ax.set_xticks(range(len(matriz)), matriz.columns, rotation=45, ha="right")
ax.set_yticks(range(len(matriz)), matriz.columns)
for i in range(len(matriz)):
    for j in range(len(matriz)):
        ax.text(j, i, matriz.iloc[i, j], ha="center", va="center", fontsize=9)
fig.colorbar(im, label="Correlación de Pearson")
ax.set_title("Matriz de correlación - clientes MercaFresh")
plt.tight_layout()
plt.show()

Detalles del código:

  • df.corr() devuelve una matriz simétrica con unos en la diagonal (toda variable correlaciona 1 consigo misma). Acepta method="pearson" (por defecto) o "spearman".
  • imshow con cmap="coolwarm" y límites vmin=-1, vmax=1 pinta rojo lo positivo, azul lo negativo y blanco lo nulo; fijar los límites es importante para que el color sea comparable entre análisis.
  • El doble bucle escribe el valor numérico en cada celda: un heatmap sin números obliga a adivinar.
  • Si tienes la librería seaborn instalada, sns.heatmap(matriz, annot=True, cmap="coolwarm", vmin=-1, vmax=1) hace lo mismo en una línea.

Cómo leerla: busca (1) celdas intensas fuera de la diagonal —relaciones fuertes—, y (2) bloques de variables muy correlacionadas entre sí, que indican información redundante.

Correlación no implica causalidad

Que X e Y se muevan juntas no demuestra que X cause Y. Hay al menos cuatro explicaciones posibles:

graph LR
    subgraph "1. X causa Y"
        A[X] --> B[Y]
    end
    subgraph "2. Y causa X"
        C[Y] --> D[X]
    end
    subgraph "3. Causa común Z"
        E[Z] --> F[X]
        E --> G[Y]
    end
    subgraph "4. Casualidad"
        H[X] -.sin relación real.- I[Y]
    end

Ejemplos:

  • Causa común (confusor). En MercaFresh, las ventas de helado correlacionan con las de gazpacho. Ninguna causa la otra: el verano causa ambas. Si el ML de demanda no incluye la estación, aprenderá relaciones espurias.
  • Dirección invertida. "Los clientes que contactan con soporte hacen más churn." ¿Contactar con soporte causa la baja? Más bien al revés: los problemas que llevan a la baja causan también el contacto con soporte.
  • Casualidad pura. Con cientos de variables, algunas correlacionarán fuerte por puro azar (existen colecciones enteras de "correlaciones espurias" célebres, como ahogamientos en piscinas vs. películas de un actor concreto). Cuantas más parejas mires, más falsos hallazgos: la lección 02-04 dará herramientas para juzgar si una relación observada es estadísticamente creíble.

Para el trabajo predictivo, una correlación estable puede bastar (si soporte-contactado predice churn, es útil aunque no sea la causa). Pero para intervenir ("¿reducimos el churn si mejoramos X?") hace falta razonamiento causal o experimentos controlados, como el test A/B que veremos en 02-04.

Relevancia para Machine Learning

  • Selección de variables. Las correlaciones de cada variable con el objetivo (target) son una primera criba barata de qué características prometen. La construcción y selección sistemática de características se desarrolla en la lección 03-06.
  • Detección de redundancia (multicolinealidad). Si dos variables de entrada correlacionan a 0,97 (p. ej., "importe con IVA" e "importe sin IVA"), aportan casi la misma información; mantener ambas desestabiliza algunos modelos lineales y complica interpretar coeficientes. De momento, quédate con la idea: bloques rojos en el heatmap = candidatos a podar; el detalle de sus efectos aparecerá al tratar la regresión y la regularización (módulos 4 y 7).
  • Comprensión del dominio. Antes de modelar, la matriz de correlación es la radiografía más rápida de qué historia cuentan los datos, y detecta también fugas de información (una variable "sospechosamente" correlacionada con el target al 0,99 suele ser una copia disfrazada de él).

Caso MercaFresh: ¿qué variables se relacionan con el churn?

El equipo quiere una primera lista de señales de abandono. El churn es binario (0/1); correlacionar una binaria con una numérica mediante Pearson se conoce como correlación punto-biserial y pandas la calcula con el mismo .corr():

# Simulamos el churn con dependencia real de dos variables
logit = (-2.2
         + 0.09 * clientes["dias_desde_ultimo_pedido"]
         + 0.8  * clientes["incidencias_entrega"]
         - 0.15 * clientes["pedidos_mes"])
p_churn = 1 / (1 + np.exp(-logit))              # transforma a probabilidad (0,1)
clientes["churn"] = rng.binomial(1, p_churn)    # Bernoulli por cliente (leccion 02-02)

correlaciones_churn = (clientes.corr(numeric_only=True)["churn"]
                       .drop("churn")
                       .sort_values(key=abs, ascending=False))
print(correlaciones_churn.round(3))

Salida aproximada:

dias_desde_ultimo_pedido    0.35
incidencias_entrega         0.20
pedidos_mes                -0.17
minutos_entrega_medio       0.09
gasto_medio                -0.02

Lectura:

  • dias_desde_ultimo_pedido es la señal más fuerte: cuanto más tiempo sin pedir, más probable la baja. Correlación positiva moderada, muy valiosa en churn.
  • incidencias_entrega suma señal: los problemas de reparto empujan al abandono.
  • pedidos_mes correlaciona en negativo: la frecuencia protege.
  • minutos_entrega_medio casi no correlaciona directamente con el churn... pero sí causa incidencias, que sí correlacionan: un ejemplo de cadena causal que la correlación simple no desenreda.
  • gasto_medio apenas aporta: candidata a descartar como predictor de churn (aunque no del negocio).

Esta tabla es exactamente el tipo de análisis exploratorio que en el módulo 4 alimentará a la regresión logística para predecir el churn; aquí nos limitamos a medir relaciones.

Errores Comunes y Consejos

  • Interpretar la magnitud de la covarianza. Solo su signo es interpretable; para magnitudes, usa siempre la correlación.
  • Concluir causalidad a partir de correlación. Antes de decir "X provoca Y", descarta la dirección inversa, los confusores y el azar; idealmente, diseña un experimento.
  • Fiarse de r sin mirar el scatter plot. El cuarteto de Anscombe (cuatro datasets con la misma r y formas radicalmente distintas) es el recordatorio clásico: dibuja antes de concluir.
  • Usar Pearson con variables ordinales o con outliers extremos. Spearman es la opción robusta en ambos casos.
  • Confundir r ≈ 0 con independencia. Pearson solo mide relación lineal; una U perfecta da r ≈ 0. Si sospechas curvas, mira el gráfico y prueba Spearman.
  • Minar correlaciones en masa sin escepticismo. Con 50 variables hay 1.225 parejas: por puro azar varias parecerán "fuertes". Prioriza las que tengan sentido de negocio y valida con las técnicas de la próxima lección.
  • Consejo: ordena las correlaciones con el target por valor absoluto (sort_values(key=abs)), como hicimos con el churn: el signo importa para interpretar, pero la fuerza es lo que prioriza.

Ejercicios

Ejercicio 1

Sin usar código: la covarianza entre minutos_entrega e incidencias de MercaFresh es 3,1. (a) ¿Puedes afirmar que la relación es fuerte? (b) Si convertimos los minutos a segundos, ¿qué le pasa a la covarianza? ¿Y a la correlación de Pearson?

Ejercicio 2

Genera dos variables con relación cuadrática pura: x = np.linspace(-3, 3, 200) e y = x**2 + ruido normal (σ=0.5). Calcula Pearson y Spearman entre x e y. Explica los resultados y qué lección práctica extraes.

Ejercicio 3

Con el DataFrame clientes del caso práctico (incluida la columna churn), calcula la matriz de correlación de Spearman y compárala con la de Pearson para la pareja (dias_desde_ultimo_pedido, churn). ¿Cambia mucho? ¿Por qué Spearman puede ser buena idea con dias_desde_ultimo_pedido?

Soluciones

Solución 1

  • (a) No. La covarianza no tiene escala interpretable: 3,1 "minutos × incidencias" puede corresponder a una relación fuerte o débil según la dispersión de cada variable. Haría falta la correlación.
  • (b) Al pasar minutos a segundos (×60), la covarianza se multiplica por 60. La correlación de Pearson no cambia en absoluto: es invariante a cambios lineales de escala, que es exactamente su razón de ser.

Solución 2

import numpy as np, pandas as pd
rng = np.random.default_rng(1)
x = np.linspace(-3, 3, 200)
y = x**2 + rng.normal(0, 0.5, 200)
s = pd.DataFrame({"x": x, "y": y})
print(s["x"].corr(s["y"]).round(3))                      # ~0.0
print(s["x"].corr(s["y"], method="spearman").round(3))   # ~0.0

Ambas salen cercanas a 0, pese a que y depende totalmente de x. Pearson falla porque la relación no es lineal; Spearman también, porque tampoco es monótona (y baja y luego sube). Lección: ningún coeficiente de correlación sustituye al scatter plot; r ≈ 0 significa "sin relación lineal/monótona", no "sin relación".

Solución 3

pareja = clientes[["dias_desde_ultimo_pedido", "churn"]]
print(pareja.corr(method="pearson").iloc[0, 1].round(3))    # ~0.35
print(pareja.corr(method="spearman").iloc[0, 1].round(3))   # similar, p.ej. ~0.33

Los valores serán parecidos (la relación simulada es aproximadamente monótona). Aun así, Spearman es defendible aquí porque dias_desde_ultimo_pedido proviene de una exponencial con cola derecha (lección 02-02): sus outliers (clientes con 60+ días inactivos) influyen menos sobre los rangos que sobre los valores brutos, haciendo la medida más robusta.

Conclusión

Ahora sabes medir relaciones entre variables: la covarianza da el signo, la correlación de Pearson añade una escala universal entre −1 y +1 para relaciones lineales, y Spearman cubre relaciones monótonas, ordinales y datos con outliers. Has construido matrices de correlación y heatmaps con pandas, has identificado las variables que más se relacionan con el churn de MercaFresh y, sobre todo, has interiorizado que correlación no implica causalidad. Pero queda una duda incómoda: ese r = 0,35 entre inactividad y churn, ¿es una señal real o podría ser fruto del azar de esta muestra concreta? Responder rigurosamente a esa pregunta —cuantificar la incertidumbre de lo que medimos en una muestra— es el trabajo de la inferencia estadística, protagonista de la próxima lección.

Curso de Machine Learning

Módulo 1: Introducción al Machine Learning

Módulo 2: Fundamentos de Estadística y Probabilidad

Módulo 3: Preprocesamiento de Datos

Módulo 4: Algoritmos de Machine Learning Supervisado

Módulo 5: Algoritmos de Machine Learning No Supervisado

Módulo 6: Evaluación y Validación de Modelos

Módulo 7: Técnicas Avanzadas y Optimización

Módulo 8: Implementación y Despliegue de Modelos

Módulo 9: Proyectos Prácticos

Módulo 10: Recursos Adicionales

© Copyright 2026. Todos los derechos reservados