Semana 8: Análisis Bivariado y Multivariado, Correlación
🎯 Objetivos de aprendizaje
Al final de esta semana podrás:
- Calcular e interpretar un coeficiente de correlación entre dos variables numéricas.
- Visualizar una relación entre dos variables numéricas con un diagrama de dispersión, y entre una variable numérica y una categórica con diagramas de caja agrupados.
- Usar una tercera variable (color, o una segunda columna categórica) para añadir una dimensión a un gráfico de dos variables.
- Comparar dos variables categóricas con una tabulación cruzada.
- Explicar, con precisión, por qué la correlación no implica causalidad.
Lección
Correlación: ¿cómo se mueven juntas dos variables numéricas?
El coeficiente de correlación de Pearson mide la fuerza y dirección de una relación lineal entre dos variables numéricas, en un rango de (negativa perfecta) pasando por (sin relación lineal) hasta (positiva perfecta):
df["math_score"].corr(df["reading_score"]) # un único número entre -1 y 1
Una regla aproximada (no universalmente acordada, pero comúnmente usada) para interpretar :
| | Interpretación aproximada | |---|---| | 0.0 – 0.2 | Muy débil / insignificante | | 0.2 – 0.4 | Débil | | 0.4 – 0.6 | Moderada | | 0.6 – 0.8 | Fuerte | | 0.8 – 1.0 | Muy fuerte |
Trata esto como una intuición de partida, no como un corte rígido — lo que cuenta como "fuerte" puede depender mucho del campo y de la pregunta específica que se esté haciendo.
Para todo el conjunto de columnas numéricas a la vez, .corr() sobre el DataFrame produce una matriz de correlación completa — el valor de cada par, incluyendo cada variable trivialmente correlacionada consigo misma:
df[["math_score", "reading_score", "writing_score"]].corr()
Un mapa de calor (heatmap) visualiza esta matriz de un vistazo, usando la intensidad del color para la fuerza de la correlación:
import seaborn as sns
import matplotlib.pyplot as plt
corr_matrix = df[["math_score", "reading_score", "writing_score"]].corr()
sns.heatmap(corr_matrix, annot=True, cmap="coolwarm", vmin=-1, vmax=1)
plt.title("Correlation between score types")
plt.show()
annot=True imprime los valores reales de en cada celda; vmin=-1, vmax=1 fija la escala de color al rango real del coeficiente, de modo que la intensidad del color sea comparable entre distintos mapas de calor en lugar de reescalarse a cualquier rango que resulte aparecer en esta matriz en particular.
Diagramas de dispersión: visualizar una relación numérica-numérica
Un diagrama de dispersión muestra la relación cruda que un coeficiente de correlación solo resume con un número:
plt.scatter(df["reading_score"], df["writing_score"], alpha=0.5)
plt.xlabel("Reading score")
plt.ylabel("Writing score")
plt.title("Reading vs. writing scores")
plt.show()
alpha=0.5 hace que los puntos sean semitransparentes, de modo que los puntos superpuestos (comunes con calificaciones enteras que se repiten en muchos estudiantes) aparecen como regiones más oscuras en lugar de ocultarse por completo unos a otros.
Añadir una tercera variable con color
Un diagrama de dispersión solo muestra dos variables directamente, pero el parámetro hue de seaborn colorea cada punto según una tercera columna (típicamente categórica), permitiéndote comprobar si una relación se mantiene de la misma forma entre grupos:
sns.scatterplot(data=df, x="reading_score", y="writing_score", hue="gender", alpha=0.6)
plt.title("Reading vs. writing scores, by gender")
plt.show()
Si las dos nubes de puntos coloreadas parecen seguir la misma tendencia general, la relación lectura/escritura probablemente no depende mucho del género; si la nube de un color está claramente desplazada o tiene una forma distinta, eso vale la pena investigarlo más a fondo — exactamente el tipo de pregunta que los gráficos facetados de la Semana 9 están construidos para responder más a fondo.
Diagramas de caja agrupados: variable numérica a través de categorías
Para comparar la distribución de una variable numérica entre categorías (no solo su promedio), usa el diagrama de caja agrupado de seaborn — la extensión multigrupo del diagrama de caja individual de la semana pasada:
sns.boxplot(data=df, x="test_preparation_course", y="math_score")
plt.title("Math score by test preparation status")
plt.show()
Esto muestra más que una simple media de groupby: si la dispersión también difiere entre grupos, y si los valores atípicos se agrupan más en un grupo que en otro.
Comparar dos variables categóricas: tabulación cruzada
.corr() solo funciona con columnas numéricas — para dos variables categóricas, pd.crosstab construye una tabla de con qué frecuencia ocurre cada combinación, el análogo categórico de una comprobación de correlación:
pd.crosstab(df["gender"], df["test_preparation_course"])
pd.crosstab(df["gender"], df["test_preparation_course"], normalize="index") # proporciones de fila en lugar de conteos
normalize="index" convierte cada fila en proporciones que suman 1 — útil para preguntar "dentro de cada género, ¿qué fracción completó la preparación del examen?" en lugar de solo conteos crudos, que pueden ser engañosos si los tamaños de los grupos en sí difieren.
La correlación no es causalidad
Un cercano a o te dice que dos variables se mueven juntas — no dice nada sobre si una causa la otra, o si ambas son impulsadas por algún tercer factor. Un ejemplo clásico de libro de texto: las ventas de helado y los incidentes de ahogamiento se correlacionan fuertemente a lo largo de un año, pero el helado no causa los ahogamientos — ambos aumentan en verano, impulsados por un tercer factor (el clima cálido, más gente nadando). Cada vez que encuentres una correlación fuerte en este dataset, pregúntate explícitamente: ¿hay un tercer factor plausible que podría explicar que ambas variables se muevan juntas?
⚠️ Errores comunes
- Tratar un alto como prueba de causalidad. Vale la pena repetir esto tan a menudo como aparezca — la correlación es una descripción de asociación, nunca una prueba de un mecanismo causal por sí sola.
- Ignorar las diferencias de tamaño de grupo al leer una tabulación cruzada. Los conteos crudos de
pd.crosstabpueden verse dramáticos puramente porque un grupo es mucho más grande —normalize="index"(o"columns") corrige esto. - Añadir demasiadas categorías de
huea un solo diagrama de dispersión. Más de 4-5 colores en un solo gráfico suele volverse más difícil de leer, no más fácil — considera el facetado de la Semana 9 (paneles separados) en su lugar una vez que un solo gráfico codificado por color se sature. - Calcular
.corr()en un DataFrame que incluye columnas no numéricas sin seleccionar primero. Las versiones recientes de pandas manejan esto descartando silenciosamente las columnas no numéricas, pero es más claro (y más seguro entre versiones) seleccionar explícitamente solo las columnas numéricas que realmente quieres, como se mostró arriba.
🧩 Retos
Calcula el coeficiente de correlación entre math_score y writing_score.
Construye la matriz de correlación 3x3 completa para las tres columnas de calificación y visualízala como un mapa de calor con los valores reales anotados en cada celda.
Crea un diagrama de caja agrupado que compare las distribuciones de math_score entre las dos categorías de lunch.
Si el tipo de lunch y math_score muestran una diferencia notable en tu diagrama de caja del reto anterior, propón un tercer factor plausible que podría explicar ambos sin que el tipo de lunch cause directamente las diferencias de calificación.
Crea un diagrama de dispersión de math_score frente a reading_score, coloreado (hue) por test_preparation_course. ¿Se ve similar la relación para ambos grupos, o los puntos de un grupo se ven desplazados?
Usando pd.crosstab con normalize="index", comprueba si el tipo de lunch y la finalización de test_preparation_course parecen estar relacionados entre sí.
🤔 Preguntas socráticas
- Es muy probable que las tres columnas de calificación (
math,reading,writing) se correlacionen fuertemente entre sí. ¿Cuál es una explicación plausible para eso — es más probable que cada materia genuinamente mejore a las demás, o que ambas sean impulsadas por algún factor subyacente compartido (p. ej. preparación académica general, hábitos de estudio)? ¿Cómo empezarías siquiera a distinguir estas posibilidades? - Un coeficiente de correlación cercano a 0 significa que no hay una relación lineal. ¿Podrían dos variables aun así tener una relación fuerte, real y no lineal (p. ej. una forma de U) y aun así mostrar ? ¿Cómo se vería eso en un diagrama de dispersión que un solo número pasaría completamente por alto?
- ¿Por qué el mapa de calor fija explícitamente
vmin=-1, vmax=1, en lugar de dejar que la escala de color se ajuste automáticamente a cualquier rango de valores que resulte aparecer en esta matriz en particular? ¿Qué podría salir mal al comparar dos mapas de calor distintos si sus escalas de color no estuvieran fijadas de la misma manera? pd.crosstab(..., normalize="index")ynormalize="columns"dan tablas con apariencia distinta a partir de los mismos datos crudos. ¿Cuál es la diferencia en la pregunta que responde cada una?- Añadir
huea un diagrama de dispersión es una forma de incorporar una tercera variable. ¿Qué perderías, comparado con el facetado de la Semana 9 (paneles separados lado a lado), si intentaras codificar por color una cuarta y quinta variable en el mismo gráfico único?