Introducción al Análisis Exploratorio de Datos (EDA)
Una vez que hemos completado la fase de limpieza e higiene de nuestras tablas, avanzamos hacia el siguiente pilar fundamental del flujo de trabajo de Machine Learning: el Análisis Exploratorio de Datos (o EDA, por sus siglas en inglés: Exploratory Data Analysis).
Podemos definir el EDA como la conversación inicial que un científico de datos mantiene con un conjunto de datos antes de tomar decisiones técnicas o algoritmos. Es la fase de reconocimiento donde se examina de forma exhaustiva la información para resumir sus características estructurales básicas, utilizando herramientas tanto estadísticas como de visualización gráfica.
¿Por qué es vital realizar un buen EDA?
- Validación de Sanidad: Permite determinar de forma matemática si los datos recopilados realmente tienen sentido lógico o si, por el contrario, exigen una fase adicional de limpieza profunda, reestructuración o recolección de nuevas variables.
- Descubrimiento de Patrones: Facilita la detección temprana de tendencias, correlaciones ocultas y anomalías espaciales en la muestra. En el entorno corporativo, los hallazgos puros derivados de un EDA riguroso suelen aportar tanto o más valor estratégico para el negocio que las propias predicciones matemáticas finales del modelo de Machine Learning.
Herramientas y Técnicas de Análisis en el EDA
El análisis exploratorio se divide operativamente en dos grandes familias de técnicas que se complementan entre sí:
Técnicas Estadísticas (Resúmenes Numéricos)
Consisten en extraer las métricas de tendencia central, dispersión y asociación matemática de las variables. Entre los estadísticos fundamentales destacan:
- Media y Mediana: Para ubicar el centro de gravedad numérico de los datos.
- Mínimos y Máximos: Para establecer los rangos operativos de las variables.
- Correlaciones: Para medir el grado de dependencia lineal entre las distintas columnas del dataset.
Técnicas Visuales (Gráficos)
Los ojos humanos procesan los patrones geométricos con mayor rapidez que las tablas de números. El EDA se apoya en tres representaciones icónicas:
- Histogramas: Para observar la distribución probabilística y la densidad de una variable numérica.
- Gráficos de Dispersión (Scatter Plots): Ideales para proyectar la relación o correlación entre dos variables continuas e identificar agrupaciones naturales (clusters).
- Diagramas de Caja (Box Plots): Para evaluar la dispersión cuartílica y geolocalizar valores atípicos (outliers).
El Ecosistema Tecnológico en Python: Durante el proceso de manipulación de tablas y cálculo de resúmenes estadísticos, la librería estándar por excelencia es Pandas. Para la generación de la capa gráfica y visual, el ecosistema se apoya firmemente en Matplotlib y Seaborn.
Caso Práctico: Análisis de Perfiles de Candidatos (Job Applicants)
Para comprender cómo interactúan estas métricas en un entorno de negocio real, consideremos un dataset corporativo diseñado para evaluar las características de un grupo de aspirantes a puestos de trabajo:
- Aplicación de la Media: Podemos calcular el promedio de las puntuaciones obtenidas en las entrevistas y desglosarlo por ciudad o función laboral. Esto permite contextualizar el rendimiento de un candidato específico frente a la media exacta de sus competidores directos en su misma región geográfica.
- Aplicación de la Moda (Valor Máximo de Frecuencia): Útil para analizar campos de texto libre o materiales de solicitud. Al extraer la moda de los textos de los currículums, la empresa puede identificar cuáles son las palabras clave o habilidades técnicas que más se repiten entre los aspirantes.
- Aplicación de Correlaciones: Mediante el cruce estadístico de la columna de “Años de Experiencia” frente a los resultados de las “Evaluaciones Técnicas”, la organización puede evaluar inmediatamente si existe una relación lineal ascendente (a mayor experiencia, mayor puntuación técnica) antes de proceder a la fase de modelado predictivo.
Muestreo de Datos (Sampling) en DataFrames
En muchas ocasiones, los científicos de datos se enfrentan a volúmenes masivos de información que saturan la memoria del sistema o ralentizan los tiempos de cómputo de los algoritmos. Para solucionar esto de manera eficiente, se recurre al muestreo aleatorio (random sampling).
Razones Técnicas para Muestrear
- Optimización Computacional: Reducir el dataset original a una muestra representativa acelera los análisis exploratorios y prototipados rápidos sin degradar la calidad de las conclusiones.
- División de Datos (Train/Test Split): Es la base para entrenar un modelo en una porción de datos aleatoria y reservar otra muestra completamente independiente para evaluar su capacidad de generalización en fases de testeo.
- Preservación de Proporciones (Muestreo Estratificado): Supongamos que trabajamos con un dataset médico para detectar una enfermedad grave que solo padece el 1% de la población mundial. Si tomamos una muestra aleatoria simple muy pequeña, corremos el riesgo de generar un subconjunto donde no haya ningún individuo enfermo o, por el contrario, donde estén sobrerrepresentados. El muestreo estratificado (stratified sampling) asegura que la muestra mantenga exactamente la proporción del 1% del evento de interés.
Implementación de muestreo con Pandas (.sample)
La librería Pandas proporciona el método integrado .sample(), diseñado específicamente para extraer filas aleatorias de un objeto DataFrame de forma óptima.
El siguiente bloque de código demuestra cómo extraer una muestra aleatoria fija de cinco filas, asegurando que no existan registros repetidos mediante el argumento replace=False (comportamiento por defecto), y seleccionando únicamente un segmento de columnas mediante indexación implícita con .iloc:
import pandas as pd
# Suponiendo que 'df' es nuestro DataFrame cargado (ej. el dataset Iris)
# 1. Extracción de una muestra aleatoria de 5 registros sin reemplazo
muestra_df = df.sample(n=5, replace=False)
# 2. Segmentación: seleccionar todas las filas extraídas (:)
# y restringir a las últimas tres columnas (-3:)
resultado_final = muestra_df.iloc[:, -3:]
# 3. Visualización del resultado
print(resultado_final)
Análisis del Output Resultante
Al ejecutar el código sobre una base de datos biológica como Iris, la consola devolverá una estructura limpia con índices aleatorios y únicamente las últimas tres columnas indexadas:
Plaintext
petal_length petal_width species
34 1.5 0.2 setosa
112 5.5 2.1 virginica
78 4.5 1.5 versicolor
14 1.2 0.2 setosa
143 5.9 2.3 virginica
- Explicación del Indexado: El operador
-3:indica a Python que empiece a contar desde la tercera columna empezando por el final de la tabla (en este caso,petal_length) y avance hasta el término del DataFrame, logrando un aislamiento preciso de los datos que queremos inspeccionar visualmente.
6. El Ecosistema de Librerías de Visualización en Python
Para llevar a cabo un Análisis Exploratorio de Datos (EDA) efectivo, Python ofrece tres herramientas principales de visualización que interactúan entre sí de forma jerárquica:
Ecosistema de Visualización en Python
┌───────────────────┐
│ Seaborn │ <- Estética avanzada y
│ (High-level API) │ gráficos estadísticos
└─────────┬─────────┘
│ (Construido sobre)
┌─────────▼─────────┐
│ Matplotlib │ <- Motor gráfico base
│ (Core Engine) │ y control absoluto
└─────────▲─────────┘
│ (Wrapper de)
┌─────────┴─────────┐
│ Pandas .plot() │ <- Prototipado rápido
│ (Quick Wrapper) │ directo desde tablas
└───────────────────┘
- Matplotlib (
matplotlib.pyplot): Es la librería fundacional y el motor gráfico estándar de Python. Ofrece un control absoluto y microscópico sobre cada elemento del gráfico (ejes, etiquetas, colores, fuentes). Su gran flexibilidad la convierte en la base de la que dependen las demás librerías. - Pandas Plotting: Consiste en una interfaz integrada (wrapper) construida directamente sobre Matplotlib. Permite generar gráficos de manera rápida mediante sintaxis abreviada directamente desde un DataFrame (ej.
df.plot()). Es ideal para inspecciones rápidas sobre la marcha, aunque carece de la flexibilidad fina de Matplotlib. - Seaborn: Una librería de alto nivel desarrollada sobre Matplotlib y diseñada específicamente para el análisis estadístico. Viene configurada con estilos visuales modernos por defecto y proporciona funciones simplificadas para trazar gráficos complejos (como mapas de calor, correlaciones cruzadas o modelos lineales) que requerirían decenas de líneas de código en Matplotlib puro.
Efecto de Integración: Cuando importas Seaborn (
import seaborn as sns) en tu entorno de trabajo, este reconfigura automáticamente las preferencias estéticas globales de Matplotlib. Así, cualquier gráfico posterior que generes usando código puro de Matplotlib adoptará el formato limpio y estilizado característico de Seaborn.
Gráficos Fundamentales con Matplotlib
Para inicializar el motor de gráficos de Matplotlib en entornos interactivos como Jupyter Notebooks, es una buena práctica incluir la directiva mágica %matplotlib inline. Esto asegura que los gráficos se rendericen e integren directamente debajo de las celdas de código.
Gráfico de Dispersión Básico (Scatter Plot)
Se utiliza para examinar visualmente la relación espacial entre dos variables numéricas continuas. Para configurarlo como un diagrama de puntos puro, debemos anular el trazado de líneas continuo mediante el parámetro ls="" (line style) y definir un marcador circular con marker="o".
import matplotlib.pyplot as plt
%matplotlib inline
# Trazado de dispersión entre longitud y ancho del sépalo
plt.plot(df["sepal_length"], df["sepal_width"], ls="", marker="o")
plt.xlabel("Sepal Length")
plt.ylabel("Sepal Width")
plt.title("Relación Sépalo")
plt.show()
Gráficos Multicapa con Leyendas
Matplotlib permite superponer múltiples series de datos sobre el mismo lienzo de forma acumulativa. Cada llamada consecutiva a plt.plot() dibuja una nueva capa de información antes de renderizar la figura final con plt.show().
# Capa 1: Datos de Sépalo (Azul por defecto)
plt.plot(df["sepal_length"], df["sepal_width"], ls="", marker="o", label="Sépalo")
# Capa 2: Datos de Pétalo (Verde/Naranja automático)
plt.plot(df["petal_length"], df["petal_width"], ls="", marker="o", label="Pétalo")
# Activar la caja de leyendas utilizando las etiquetas 'label'
plt.legend()
plt.title("Comparativa de Sépalo vs Pétalo")
plt.show()
Histogramas de Distribución
Para analizar la distribución probabilística de una sola columna numérica, utilizamos la función plt.hist(). El parámetro bins determina en cuántos intervalos o “barras” se fragmenta el rango total de los datos.
# Histograma con 25 contenedores de frecuencia
plt.hist(df["sepal_length"], bins=25)
plt.xlabel("Longitud del Sépalo")
plt.ylabel("Frecuencia")
plt.show()
Personalización Avanzada y Enfoque Orientado a Objetos
Cuando se requiere construir cuadros de mando (dashboards) complejos o gráficos con modificaciones estructurales estrictas, la API orientada a objetos de Matplotlib mediante plt.subplots() es la opción recomendada. Esta función separa el lienzo general (fig) del recuadro o sistema de ejes de dibujo (ax).
El siguiente script genera un gráfico de barras horizontales (ax.barh) para evaluar los primeros 10 registros de la muestra, aplicando desfases matemáticos en las etiquetas para centrarlas perfectamente en el medio de cada barra:
import numpy as np
# 1. Crear la estructura orientada a objetos (Lienzo e Hilera de ejes)
fig, ax = plt.subplots(figsize=(6, 4))
# 2. Generar índices de posición (0 a 9) y graficar barras horizontales
posiciones = np.arange(10)
ax.barh(posiciones, df["sepal_width"].iloc[:10], align="center")
# 3. Ajustar los ticks para que queden centrados en cada barra
# Desfasamos el rango para colocar el marcador visual en el medio geométrico
ax.set_yticks(posiciones)
ax.set_yticklabels(range(1, 11))
# 4. Inyección de metadatos de texto mediante el objeto 'ax'
ax.set(xlabel="Ancho del Sépalo (cm)", ylabel="Índice del Candidato", title="Análisis de Muestra Corta")
plt.show()
Visualización Rápida con Sintaxis de Pandas
Si los datos ya están estructurados en un DataFrame de Pandas, podemos encadenar operaciones de agregación estadística (como .groupby()) directamente con el método de asistencia visual .plot(), reduciendo la cantidad de código necesario.
Python
# 1. Agrupar por especie y calcular el promedio de todas las métricas
resumen_especies = df.groupby("species").mean()
# 2. Trazar un gráfico de barras directamente desde el DataFrame agrupado
resumen_especies.plot(
kind="bar",
color=["red", "blue", "black", "green"],
fontsize=10,
figsize=(4, 4)
)
plt.ylabel("Promedio (cm)")
plt.title("Métricas Promedio por Especie")
plt.show()
Visualizaciones Avanzadas con Seaborn
Gráfico de Pares (Pair Plot)
Es una de las funciones más potentes de Seaborn para el análisis exploratorio. sns.pairplot() genera de forma automática una matriz de gráficos cruzados entre todas las variables numéricas del dataset.
- Fuera de la diagonal: Muestra gráficos de dispersión (scatter plots) para evaluar correlaciones entre pares de variables.
- En la diagonal: Al cruzar una variable consigo misma, el algoritmo la sustituye automáticamente por curvas de densidad o histogramas de distribución.
- El parámetro
hue: Segmenta y colorea los puntos según una variable categórica (como la especie), lo que permite identificar visualmente si las clases son linealmente separables.
import seaborn as sns
# Matriz de correlación visual segmentada por especies
sns.pairplot(data=df, hue="species", size=2.5)
plt.show()
Gráfico de Densidad Hexagonal (Hexbin Joint Plot)
Cuando trabajamos con miles de registros, un gráfico de dispersión tradicional sufre de saturación (overplotting), impidiendo ver dónde se concentran realmente los puntos. El gráfico sns.jointplot con el parámetro kind="hex" agrupa los puntos espaciales en celdas hexagonales: cuanto más oscuro es el hexágono, mayor es la densidad de registros en esa zona. Además, incluye las distribuciones marginales en los márgenes superior derecho.
# Gráfico conjunto de densidad hexagonal con distribuciones marginales
sns.jointplot(data=df, x="sepal_length", y="sepal_width", kind="hex")
plt.show()
Segmentación por Rejillas de Facetas (Facet Grid)
El objeto FacetGrid permite subdividir el dataset en función de una o más variables categóricas, creando subgráficos independientes (facets) organizados en columnas o filas. Esto facilita la comparación directa de distribuciones entre diferentes categorías.
# 1. Definir la cuadrícula estructural basada en la columna de especies
grid = sns.FacetGrid(data=df, col="species", margin_titles=True)
# 2. Mapear un histograma de la variable deseada en cada una de las facetas
grid.map(plt.hist, "sepal_width", bins=10)
plt.show()
Visualización Avanzada: Integración de Pandas y Seaborn
El Análisis Exploratorio de Datos (EDA) se potencia cuando combinamos la estructuración rápida de datos con capacidades de visualización avanzadas. A continuación, analizaremos cómo automatizar y sofisticar nuestros gráficos utilizando la sintaxis nativa de Pandas y el motor estadístico de Seaborn.
Sintaxis de Trazado de Pandas con Agrupaciones (.groupby)
Por defecto, al llamar al método .plot() en un DataFrame de Pandas, la librería intenta trazar un gráfico de líneas. Sin embargo, cuando se combina con funciones de agregación estadística como .groupby(), podemos mapear resúmenes multivariables rápidamente.
Si quisiéramos analizar el promedio de las dimensiones del dataset Iris (longitud y ancho de pétalos y sépalos) para cada una de las especies, podemos definir colores personalizados y un tamaño de lienzo compacto de $4 \times 4$ pulgadas mediante el argumento figsize:
Python
# Agrupar por la columna objetivo y calcular la media de cada característica
df_resumen = df.groupby("species").mean()
# Generar gráfico de barras con parámetros personalizados
df_resumen.plot(
kind="bar",
color=["red", "blue", "black", "green"],
fontsize=10,
figsize=(4, 4)
)Al ejecutar este bloque, el eje $X$ mostrará las categorías (setosa, versicolor, virginica) y las barras representarán las medias de cada característica, diferenciadas según la paleta de colores inyectada.
Matrices de Correlación Visual: sns.pairplot
Una de las utilidades más potentes de Seaborn para el análisis exploratorio es el Pair Plot (gráfico de pares). Mediante una sola línea de código, sns.pairplot() construye una matriz tridimensional que cruza todas las variables numéricas del DataFrame entre sí.
- Fuera de la diagonal: Se generan gráficos de dispersión (scatter plots) automáticos que revelan la relación espacial y la correlación entre dos variables distintas.
- En la diagonal: Dado que cruzar una variable consigo misma generaría una línea recta sin valor analítico, Seaborn la sustituye de forma inteligente por un histograma o una curva de densidad para mostrar la distribución univariable.
- El argumento
hue: Al igualar este parámetro a una columna categórica (comohue="species"), el algoritmo segmenta y colorea los datos por clases. Esto permite identificar de un vistazo si las poblaciones o perfiles de negocio son linealmente separables.
import seaborn as sns
import matplotlib.pyplot as plt
# Importar Seaborn e implementar el gráfico de pares global
sns.pairplot(data=df, hue="species", height=2.5)
plt.show()
💡 Caso de Uso en Negocios: Esta misma lógica se aplica al entorno corporativo. Si sustituyéramos las variables biológicas por métricas como Inversión en Publicidad (Ad Spend) y Retorno de Ingresos (Revenue), el pair plot nos mostraría instantáneamente la dispersión y efectividad de las campañas, además de la distribución de las ventas en el mismo lienzo.
Gráficos de Densidad Hexagonal: sns.jointplot
Cuando un conjunto de datos contiene miles de registros, los gráficos de dispersión tradicionales sufren de saturación de puntos (overplotting). Los marcadores se superponen unos sobre otros creando masas de color uniformes donde es imposible determinar dónde se concentra la mayoría de los datos.
Para resolver este problema, Seaborn ofrece el gráfico de agrupación hexagonal (Hexbin plot), invocable mediante sns.jointplot() con el argumento kind="hex".
Características del Gráfico Hexagonal:
- Contenedores Geométricos: El espacio bidimensional se divide en hexágonos regulares que actúan como “contenedores de frecuencia”.
- Escala de Densidad: Las celdas hexagonales se colorean con una escala de intensidad. Los hexágonos más oscuros denotan una densidad de datos muy alta (zonas de solapamiento frecuente), mientras que los más claros representan registros aislados.
- Márgenes de Distribución: En las secciones superior y derecha del gráfico, se renderizan de forma automática los histogramas univariables de los ejes $X$ e $Y$, permitiendo un doble diagnóstico en una sola mirada.
Python
# Trazado conjunto con densidad de hexágonos e histogramas marginales
sns.jointplot(data=df, x="sepal_length", y="sepal_width", kind="hex")
plt.show()
Segmentación Estructural mediante sns.FacetGrid
Cuando el objetivo del análisis es aislar por completo el comportamiento de una variable según subcategorías específicas (similar a realizar operaciones analíticas en paralelo), la herramienta ideal es FacetGrid.
Una rejilla de facetas (FacetGrid) toma un criterio de segmentación (por ejemplo, las distintas especies) y genera un lienzo independiente para cada una, ordenándolas en columnas. Luego, mediante el método .map(), podemos “inyectar” el tipo de gráfico que deseamos replicar en cada contenedor.
# 1. Inicializar la cuadrícula estructurando las columnas según la especie
grid = sns.FacetGrid(data=df, col="species", margin_titles=True)
# 2. Mapear un histograma del ancho del sépalo en cada una de las facetas creadas
grid.map(plt.hist, "sepal_width", bins=10)
plt.show()
Si quisiéramos evaluar una característica diferente bajo la misma estructura, simplemente reconfiguramos el mapeo sobre el objeto:
# 3. Reutilizar la cuadrícula para analizar la longitud del sépalo por separado
grid_longitud = sns.FacetGrid(data=df, col="species", margin_titles=True)
grid_longitud.map(plt.hist, "sepal_length", bins=10)
plt.show()
Conclusiones del Módulo EDA
Con estas metodologías concluimos la base teórica del Análisis Exploratorio de Datos:
- Métricas y Gráficos en Sintonía: El EDA combina la precisión numérica de los resúmenes estadísticos (medias, medianas, correlaciones) con el impacto visual de los histogramas y diagramas de dispersión.
- Ecosistema Jerárquico: Recordamos que Matplotlib actúa como el motor flexible de bajo nivel, Pandas como la vía de prototipado veloz y Seaborn como la solución óptima para análisis estadísticos complejos y estéticos.
- Muestreo Estratificado: Al enfrentarnos a datos masivos o desbalanceados, el submuestreo controlado protege la fidelidad de las proporciones poblacionales.