Análisis de Correlación
Calcula y visualiza las correlaciones de Pearson y Spearman, detecta la multicolinealidad e interpreta las matrices de correlación.
- Calcular los coeficientes de correlación de Pearson y Spearman e interpretar sus valores
- Construir matrices de correlación y mapas de calor para un panorama general de las relaciones multivariadas
- Distinguir la correlación de la causalidad e identificar los factores de confusión
- Detectar la multicolinealidad y decidir cuándo eliminar o combinar características correlacionadas
La correlación mide la fuerza y la dirección de una relación lineal entre dos variables numéricas. Esta lección cubre la correlación de Pearson y de Spearman, cómo construir y leer mapas de calor de correlación, y cómo detectar la multicolinealidad, el destructor silencioso de los modelos de regresión.
Conceptos clave
Correlación de Pearson
La correlación de Pearson (r) mide la asociación lineal entre dos variables continuas:
import pandas as pd
import numpy as np
# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")
# Compute Pearson correlation between two variables
r = df["math score"].corr(df["reading score"], method="pearson")
print(f"Pearson r (math vs reading): {r:.4f}")Interpretación de r:
| Rango | Fuerza | Dirección |
|---|---|---|
| 0.00 – 0.19 | Muy débil | , |
| 0.20 – 0.39 | Débil | , |
| 0.40 – 0.59 | Moderada | , |
| 0.60 – 0.79 | Fuerte | , |
| 0.80 – 1.00 | Muy fuerte | , |
El signo indica la dirección: positiva (ambas aumentan juntas) o negativa (una aumenta mientras la otra disminuye).
Correlación de Spearman
La correlación de Spearman (ρ) mide las relaciones monótonas, funciona con datos ordinales y es robusta a los valores atípicos:
rho = df["math score"].corr(df["reading score"], method="spearman")
print(f"Spearman ρ (math vs reading): {rho:.4f}")
# Compare Pearson vs Spearman
pearson = df["math score"].corr(df["reading score"], method="pearson")
spearman = df["math score"].corr(df["reading score"], method="spearman")
print(f"Pearson: {pearson:.4f} | Spearman: {spearman:.4f}")Cuando Pearson y Spearman divergen:
- Spearman > Pearson: la relación es monótona pero no lineal (curva)
- Pearson > Spearman: los valores atípicos están inflando la correlación lineal
- Ambos similares: la relación es lineal y monótona
Matriz de correlación
Calcula las correlaciones de todas las columnas numéricas a la vez:
# Full correlation matrix
num_cols = df.select_dtypes(include="number")
corr_matrix = num_cols.corr(method="pearson")
print(corr_matrix.round(3))Visualización con mapa de calor
Un mapa de calor hace que la matriz de correlación sea visual y escaneable:
import seaborn as sns
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(
corr_matrix,
annot=True, # show correlation values
fmt=".2f", # two decimal places
cmap="RdBu_r", # red-blue diverging colormap
center=0, # center colormap at zero
vmin=-1, vmax=1, # full correlation range
square=True, # square cells
linewidths=0.5, # cell borders
ax=ax
)
ax.set_title("Correlation Matrix — Students Performance")
plt.tight_layout()
plt.show()Mapa de calor triangular (eliminar la redundancia)
La matriz completa es simétrica, el triángulo superior repite el triángulo inferior. Elimínalo:
import numpy as np
mask = np.triu(np.ones_like(corr_matrix, dtype=bool))
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(
corr_matrix,
mask=mask,
annot=True,
fmt=".2f",
cmap="RdBu_r",
center=0,
vmin=-1, vmax=1,
square=True,
linewidths=0.5,
ax=ax
)
ax.set_title("Correlation Matrix (Lower Triangle)")
plt.tight_layout()
plt.show()Gráfico de pares para un panorama multivariado
Los gráficos de pares muestran cada relación por pares en una sola figura:
sns.pairplot(
df,
vars=["math score", "reading score", "writing score"],
hue="gender",
diag_kind="kde",
plot_kws={"alpha": 0.4},
height=3
)
plt.suptitle("Pair Plot: Scores by Gender", y=1.02)
plt.show()La correlación no implica causalidad
La advertencia más importante de la estadística. Tres razones por las que una correlación puede ser engañosa:
- Confusión: una tercera variable impulsa ambas. Ejemplo: la educación de los padres se correlaciona con los puntajes de los estudiantes, pero podría ser el ingreso lo que impulsa ambas.
- Causalidad inversa: la dirección está al revés. Ejemplo: ¿la preparación para el examen causa puntajes más altos, o los estudiantes de alto rendimiento se autoseleccionan en la preparación?
- Correlación espuria: dos variables no relacionadas se correlacionan por casualidad. Ejemplo: las ventas de helado y las tasas de ahogamiento aumentan ambas en verano (la temperatura es el factor de confusión).
# Check for confounders
# Does the math-reading correlation change after controlling for gender?
for gender in df["gender"].unique():
subset = df[df["gender"] == gender]
r = subset["math score"].corr(subset["reading score"])
print(f"{gender}: math-reading r = {r:.3f}")Detección de multicolinealidad
Cuando dos o más características de un modelo de regresión están muy correlacionadas, la multicolinealidad infla los errores estándar y vuelve inestables las estimaciones de los coeficientes.
Reglas prácticas:
- |r| > 0.7: investiga, puede que necesites eliminar una variable
- |r| > 0.9: multicolinealidad grave, elimina o combina
# Find highly correlated pairs
high_corr_pairs = []
for i in range(len(corr_matrix.columns)):
for j in range(i+1, len(corr_matrix.columns)):
if abs(corr_matrix.iloc[i, j]) > 0.7:
high_corr_pairs.append((
corr_matrix.columns[i],
corr_matrix.columns[j],
corr_matrix.iloc[i, j]
))
print("Highly correlated pairs (|r| > 0.7):")
for col1, col2, r in high_corr_pairs:
print(f" {col1} <-> {col2}: r = {r:.3f}")Inténtalo
Construye un análisis de correlación completo para el conjunto de datos Students Performance.
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")
num_cols = df.select_dtypes(include="number")
corr = num_cols.corr()
# Triangular heatmap
mask = np.triu(np.ones_like(corr, dtype=bool))
fig, ax = plt.subplots(figsize=(8, 6))
sns.heatmap(corr, mask=mask, annot=True, fmt=".2f", cmap="RdBu_r",
center=0, vmin=-1, vmax=1, square=True, linewidths=0.5, ax=ax)
ax.set_title("Correlation Heatmap")
plt.tight_layout()
plt.show()
# Pair plot
sns.pairplot(df, vars=["math score", "reading score", "writing score"],
hue="gender", diag_kind="kde", plot_kws={"alpha": 0.4}, height=3)
plt.suptitle("Pair Plot: Scores by Gender", y=1.02)
plt.show()
# Find high correlations
for i in range(len(corr.columns)):
for j in range(i+1, len(corr.columns)):
if abs(corr.iloc[i, j]) > 0.5:
print(f"{corr.columns[i]} <-> {corr.columns[j]}: r = {corr.iloc[i, j]:.3f}")Conclusiones clave
- Pearson mide la correlación lineal; Spearman mide la correlación monótona, usa ambos cuando la relación podría ser no lineal
- Los mapas de calor hacen visuales las matrices de correlación; los mapas de calor triangulares eliminan la información redundante
- Los gráficos de pares dan un panorama multivariado completo con distribuciones marginales
- La correlación nunca implica causalidad, los factores de confusión, la causalidad inversa y las correlaciones espurias siempre son posibles
- La multicolinealidad (|r| > 0.7) infla los errores estándar en los modelos de regresión y debe abordarse
Desafío de práctica
Calcula las correlaciones de Pearson y de Spearman para todos los pares de puntajes. Crea una figura con dos mapas de calor lado a lado (uno para cada método). Anota qué pares tienen la mayor discrepancia entre Pearson y Spearman y explica qué significa esa discrepancia.
🧩 Desafío, piensa primero, luego revela
import pandas as pd
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
# students-performance.csv ships with the course — load it from the browser file system.
df = pd.read_csv("students-performance.csv")
scores = df[["math score", "reading score", "writing score"]]
pearson_corr = scores.corr(method="pearson")
spearman_corr = scores.corr(method="spearman")
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Pearson
sns.heatmap(pearson_corr, annot=True, fmt=".3f", cmap="RdBu_r", center=0,
vmin=-1, vmax=1, square=True, linewidths=0.5, ax=axes[0])
axes[0].set_title("Pearson Correlation")
# Spearman
sns.heatmap(spearman_corr, annot=True, fmt=".3f", cmap="RdBu_r", center=0,
vmin=-1, vmax=1, square=True, linewidths=0.5, ax=axes[1])
axes[1].set_title("Spearman Correlation")
plt.tight_layout()
plt.show()
# Find discrepancies
mask = np.triu(np.ones_like(pearson_corr, dtype=bool))
diff = (pearson_corr - spearman_corr).abs()
for i in range(len(diff.columns)):
for j in range(i+1, len(diff.columns)):
d = diff.iloc[i, j]
if d > 0.01:
print(f"{diff.columns[i]} <-> {diff.columns[j]}: "
f"Pearson={pearson_corr.iloc[i,j]:.3f}, "
f"Spearman={spearman_corr.iloc[i,j]:.3f}, "
f"Diff={d:.3f}")1. ¿Cuál es la diferencia entre la correlación de Pearson y la de Spearman?
2. ¿Qué significa una correlación de 0?
3. ¿Por qué deberías comprobar la multicolinealidad?