tutoriales.com

Análisis Exploratorio de Datos con Pandas: El Arte de Desvelar Secretos Ocultos en tus Datos

Este tutorial te guiará a través del fascinante mundo del Análisis Exploratorio de Datos (EDA) utilizando las potentes librerías Pandas y NumPy en Python. Aprenderás técnicas esenciales para inspeccionar, limpiar, transformar y visualizar tus datos, descubriendo patrones y anomalías ocultas que son cruciales para cualquier proyecto de ciencia de datos. Prepárate para convertirte en un detective de datos.

Intermedio20 min de lectura31 views12 de marzo de 2026Reportar error

Análisis Exploratorio de Datos con Pandas: El Arte de Desvelar Secretos Ocultos en tus Datos 🕵️‍♀️

Bienvenido a este tutorial exhaustivo sobre el Análisis Exploratorio de Datos (EDA) con Pandas y NumPy. Si estás dando tus primeros pasos en la ciencia de datos o buscas afinar tus habilidades, entender y aplicar el EDA es fundamental. No es solo una serie de pasos; es una mentalidad, un proceso detectivesco para comprender a fondo tus datos antes de sumergirte en modelos complejos.

El EDA te permite formular hipótesis, identificar problemas, detectar valores atípicos y preparar tus datos de la mejor manera para el modelado. Es el primer gran paso para transformar datos crudos en información valiosa. ¡Vamos a desvelar los secretos que tus datos guardan!

🔥 Importante: El EDA es un proceso iterativo. No esperes obtener todas las respuestas en el primer intento. La clave es experimentar, visualizar y hacer preguntas constantemente.

🎯 ¿Qué es el Análisis Exploratorio de Datos (EDA)?

El Análisis Exploratorio de Datos (EDA) es una aproximación al análisis de datos que emplea una variedad de técnicas (principalmente visuales y estadísticas) para maximizar la comprensión de un conjunto de datos, descubrir patrones, detectar anomalías, probar hipótesis y verificar supuestos con la ayuda de resúmenes estadísticos y representaciones gráficas.

"Los datos son lo que obtienes cuando el mundo se interpone en el camino de la información." - Nathan Myhrvold

📖 El Ciclo de Vida del EDA

El EDA generalmente sigue un ciclo que puede resumirse en los siguientes pasos:

1. Carga y Visión General: Importar los datos y obtener una primera impresión.
2. Limpieza de Datos: Manejar valores faltantes, duplicados y formatos incorrectos.
3. Análisis Univariado: Entender cada variable individualmente.
4. Análisis Bivariado/Multivariado: Explorar relaciones entre variables.
5. Visualización: Crear gráficos para comunicar hallazgos.
6. Ingeniería de Características (Opcional): Crear nuevas variables si es necesario.

🛠️ Herramientas Fundamentales: Pandas y NumPy

Pandas es una librería de código abierto que proporciona estructuras de datos de alto rendimiento y herramientas de análisis de datos fáciles de usar para el lenguaje de programación Python. Su estructura de datos principal es el DataFrame, que simula una tabla de base de datos o una hoja de cálculo. Es el caballo de batalla para manipular datos tabulares.

NumPy (Numerical Python) es la base de casi todo el ecosistema científico de Python. Proporciona un objeto de matriz multidimensional de alto rendimiento y herramientas para trabajar con estas matrices. Pandas se construye sobre NumPy, aprovechando su eficiencia para operaciones numéricas.

90% Esencialidad en Ciencia de Datos

Instalación (si aún no las tienes)

Si no tienes estas librerías instaladas, puedes hacerlo fácilmente con pip:

pip install pandas numpy matplotlib seaborn

matplotlib y seaborn son librerías de visualización que utilizaremos más adelante.


🚀 Paso 1: Carga y Primera Inspección de Datos

El primer paso es siempre cargar tus datos y obtener una vista previa rápida. Usaremos un conjunto de datos ficticio de "ventas de productos" para este tutorial.

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns

# Configuración de visualización para gráficos
sns.set_style("whitegrid")
plt.rcParams['figure.figsize'] = (10, 6)
plt.rcParams['font.size'] = 12

# Crear un DataFrame de ejemplo
data = {
    'ID_Producto': range(1, 21),
    'Categoria': np.random.choice(['Electrónica', 'Ropa', 'Alimentos', 'Hogar'], 20),
    'Precio': np.round(np.random.uniform(10, 500, 20), 2),
    'Cantidad_Vendida': np.random.randint(1, 100, 20),
    'Fecha_Venta': pd.to_datetime(pd.date_range(start='2023-01-01', periods=20, freq='D')),
    'Region': np.random.choice(['Norte', 'Sur', 'Este', 'Oeste'], 20),
    'Valoracion_Cliente': np.random.choice([1, 2, 3, 4, 5, np.nan], 20, p=[0.05, 0.1, 0.2, 0.3, 0.3, 0.05]),
    'Descuento': np.random.choice([True, False], 20, p=[0.3, 0.7])
}
df = pd.DataFrame(data)

# Introducir algunos valores nulos y duplicados intencionadamente
df.loc[[2, 7, 15], 'Precio'] = np.nan
df.loc[[5, 12], 'Cantidad_Vendida'] = np.nan
df.loc[1, 'Categoria'] = np.nan
df.loc[0, 'ID_Producto'] = 1 # Duplicado
df.loc[1, 'ID_Producto'] = 2 # Duplicado

print("Primeras 5 filas del DataFrame:")
print(df.head())
print("\nÚltimas 5 filas del DataFrame:")
print(df.tail())

df.info() y df.describe(): Tus Mejores Amigos

df.info() te da un resumen conciso del DataFrame, incluyendo el tipo de datos de cada columna y la cantidad de valores no nulos. Es crucial para identificar valores faltantes y tipos de datos incorrectos.

df.describe() genera estadísticas descriptivas para columnas numéricas, como la media, desviación estándar, valores mínimos y máximos, y los cuartiles. Es excelente para obtener una visión rápida de la distribución de los datos.

print("\nInformación general del DataFrame:")
df.info()

print("\nEstadísticas descriptivas del DataFrame:")
print(df.describe(include='all')) # include='all' para incluir columnas no numéricas
💡 Consejo: `df.describe(include='all')` es muy útil para ver un resumen de las columnas categóricas, mostrando el recuento, valores únicos, el valor más frecuente (`top`) y su frecuencia (`freq`).

🩹 Paso 2: Limpieza de Datos

Los datos del mundo real rara vez están limpios. El EDA es el momento perfecto para abordar valores faltantes, duplicados y tipos de datos incorrectos.

Valores Faltantes (NaN)

Los valores faltantes pueden distorsionar tus análisis y modelos. Es vital identificarlos y decidir cómo manejarlos. Las estrategias comunes incluyen:

  • Eliminar: Eliminar filas o columnas con muchos NaN. Útil si hay pocos NaN o si la columna es irrelevante.
  • Imputar: Rellenar los NaN con un valor (media, mediana, moda, un valor constante, interpolación). La elección depende del contexto y la distribución de los datos.
print("\nValores faltantes por columna:")
print(df.isnull().sum())

# Visualización de valores faltantes
plt.figure(figsize=(10, 6))
sns.heatmap(df.isnull(), cbar=False, cmap='viridis')
plt.title('Mapa de Calor de Valores Faltantes')
plt.show()

# Estrategias para manejar valores faltantes
# 1. Imputar 'Precio' con la mediana
df['Precio'].fillna(df['Precio'].median(), inplace=True)

# 2. Imputar 'Cantidad_Vendida' con la media
df['Cantidad_Vendida'].fillna(df['Cantidad_Vendida'].mean(), inplace=True)

# 3. Imputar 'Categoria' con la moda (el valor más frecuente)
df['Categoria'].fillna(df['Categoria'].mode()[0], inplace=True)

# 4. Para 'Valoracion_Cliente', podríamos rellenar con un valor específico (ej. 0 o la media), o eliminar las filas si son pocas.
# En este caso, lo rellenaremos con la media redondeada.
df['Valoracion_Cliente'].fillna(df['Valoracion_Cliente'].mean().round(), inplace=True)

print("\nValores faltantes después de la imputación:")
print(df.isnull().sum())

Duplicados

Los registros duplicados pueden sesgar tus análisis. Identificarlos y eliminarlos es un paso crucial.

print("\nNúmero de filas duplicadas (basado en todas las columnas):")
print(df.duplicated().sum())

# Para este ejemplo, hemos introducido duplicados en 'ID_Producto'. Vamos a verificar y eliminar.
print("\nFilas duplicadas basadas en 'ID_Producto':")
print(df[df.duplicated(subset=['ID_Producto'], keep=False)])

# Eliminar duplicados, manteniendo la primera ocurrencia
df_cleaned = df.drop_duplicates(subset=['ID_Producto'], keep='first')

print("\nDimensiones del DataFrame después de eliminar duplicados:")
print(df_cleaned.shape)
⚠️ Advertencia: Al eliminar duplicados, asegúrate de entender qué `subset` de columnas usar y qué `keep` (first, last, False) es apropiado para tu caso. Eliminar ciegamente puede llevar a la pérdida de información útil.

Tipos de Datos (dtypes)

Asegurarte de que cada columna tiene el tipo de dato correcto es esencial. Por ejemplo, una columna numérica que se interpreta como object (cadena) no permitirá operaciones matemáticas.

print("\nTipos de datos actuales:")
print(df_cleaned.dtypes)

# 'Fecha_Venta' ya es datetime gracias a pd.to_datetime en la creación.
# 'Descuento' es booleano.
# Si 'Valoracion_Cliente' fuese float, podríamos quererla como int si solo tiene enteros.
# df_cleaned['Valoracion_Cliente'] = df_cleaned['Valoracion_Cliente'].astype(int)

# Asegurar que 'ID_Producto' sea de tipo entero si no lo es
df_cleaned['ID_Producto'] = df_cleaned['ID_Producto'].astype(int)
print("\nTipos de datos después de ajustes:")
print(df_cleaned.dtypes)

✨ Paso 3: Análisis Univariado

El análisis univariado se enfoca en entender cada variable de forma individual. Es aquí donde las estadísticas descriptivas y las visualizaciones simples cobran protagonismo.

Variables Numéricas

Para variables numéricas como Precio y Cantidad_Vendida:

  • Histogramas y KDE (Estimación de la Densidad del Kernel): Muestran la distribución de los datos. Ayudan a identificar asimetrías, modas y valores atípicos.
  • Box Plots (Diagramas de Caja): Muestran la mediana, cuartiles y valores atípicos. Ideales para comparar distribuciones.
# Histogramas y KDE para variables numéricas
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
sns.histplot(df_cleaned['Precio'], kde=True, color='#4A90D9')
plt.title('Distribución de Precios')
plt.xlabel('Precio')
plt.ylabel('Frecuencia')

plt.subplot(1, 2, 2)
sns.histplot(df_cleaned['Cantidad_Vendida'], kde=True, color='#50C878')
plt.title('Distribución de Cantidad Vendida')
plt.xlabel('Cantidad Vendida')
plt.ylabel('Frecuencia')

plt.tight_layout()
plt.show()

# Box plots para variables numéricas (para detectar outliers)
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
sns.boxplot(y=df_cleaned['Precio'], color='#FFD93D')
plt.title('Box Plot de Precios')
plt.ylabel('Precio')

plt.subplot(1, 2, 2)
sns.boxplot(y=df_cleaned['Cantidad_Vendida'], color='#FF6B6B')
plt.title('Box Plot de Cantidad Vendida')
plt.ylabel('Cantidad Vendida')

plt.tight_layout()
plt.show()
¿Qué nos dicen los histogramas y box plots? Un **histograma** muestra la forma general de la distribución de los datos. Un pico alto indica una mayor concentración de valores en ese rango. Un **box plot** resume la distribución de un conjunto de datos mostrando cinco números clave: el mínimo, el primer cuartil (Q1), la mediana, el tercer cuartil (Q3) y el máximo. Los puntos fuera de los 'bigotes' son considerados valores atípicos (outliers).

Variables Categóricas

Para variables categóricas como Categoria y Region:

  • Gráficos de Barras: Muestran la frecuencia de cada categoría. Ideales para comparar proporciones.
# Gráficos de barras para variables categóricas
plt.figure(figsize=(12, 5))

plt.subplot(1, 2, 1)
sns.countplot(data=df_cleaned, x='Categoria', palette='viridis')
plt.title('Distribución por Categoría de Producto')
plt.xlabel('Categoría')
plt.ylabel('Número de Productos')
plt.xticks(rotation=45, ha='right')

plt.subplot(1, 2, 2)
sns.countplot(data=df_cleaned, x='Region', palette='plasma')
plt.title('Distribución de Ventas por Región')
plt.xlabel('Región')
plt.ylabel('Número de Ventas')

plt.tight_layout()
plt.show()

# Conteo de valores únicos para 'Descuento'
print("\nConteo de productos con/sin descuento:")
print(df_cleaned['Descuento'].value_counts())

🤝 Paso 4: Análisis Bivariado y Multivariado

Aquí exploramos las relaciones entre dos o más variables. Este es el corazón del EDA, donde realmente se empiezan a desvelar patrones y correlaciones.

Numérica vs. Numérica

  • Gráficos de Dispersión (Scatter Plots): Ideales para ver la relación entre dos variables numéricas. Permiten identificar correlaciones y agrupaciones.
  • Matrices de Correlación: Muestran los coeficientes de correlación entre pares de variables numéricas. Un mapa de calor (heatmap) es excelente para visualizarla.
# Gráfico de dispersión: Precio vs. Cantidad_Vendida
plt.figure(figsize=(8, 6))
sns.scatterplot(data=df_cleaned, x='Precio', y='Cantidad_Vendida', hue='Categoria', size='Valoracion_Cliente', sizes=(20, 400), palette='tab10')
plt.title('Precio vs. Cantidad Vendida por Categoría y Valoración')
plt.xlabel('Precio')
plt.ylabel('Cantidad Vendida')
plt.legend(title='Categoría', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.tight_layout()
plt.show()

# Matriz de Correlación
correlation_matrix = df_cleaned[['Precio', 'Cantidad_Vendida', 'Valoracion_Cliente']].corr()
print("\nMatriz de Correlación:\n", correlation_matrix)

plt.figure(figsize=(7, 6))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', fmt=".2f", linewidths=.5)
plt.title('Matriz de Correlación de Variables Numéricas')
plt.show()
📌 Nota: Los valores de correlación van de -1 a 1. 1 significa correlación positiva perfecta, -1 negativa perfecta y 0 no correlación lineal. Recuerda que correlación no implica causalidad.

Categórica vs. Numérica

  • Box Plots o Violin Plots por Categoría: Permiten comparar la distribución de una variable numérica a través de diferentes categorías.
  • Gráficos de Barras Agrupadas o Apiladas: Útiles para mostrar agregados (media, suma) de una variable numérica por categorías.
# Box plot de Precio por Categoría
plt.figure(figsize=(10, 6))
sns.boxplot(data=df_cleaned, x='Categoria', y='Precio', palette='Set3')
plt.title('Distribución de Precios por Categoría')
plt.xlabel('Categoría')
plt.ylabel('Precio')
plt.xticks(rotation=45, ha='right')
plt.show()

# Suma de Cantidad_Vendida por Región
sales_by_region = df_cleaned.groupby('Region')['Cantidad_Vendida'].sum().reset_index()

plt.figure(figsize=(8, 6))
sns.barplot(data=sales_by_region, x='Region', y='Cantidad_Vendida', palette='rocket')
plt.title('Cantidad Total Vendida por Región')
plt.xlabel('Región')
plt.ylabel('Cantidad Total Vendida')
plt.show()

Categórica vs. Categórica

  • Tablas de Contingencia (Crosstabs): Muestran la frecuencia de combinaciones de categorías.
  • Gráficos de Barras Apiladas o Agrupadas: Para visualizar las proporciones entre categorías.
# Tabla de Contingencia: Categoria vs. Descuento
crosstab_data = pd.crosstab(df_cleaned['Categoria'], df_cleaned['Descuento'])
print("\nTabla de Contingencia (Categoría vs. Descuento):\n", crosstab_data)

# Gráfico de barras apiladas o agrupadas
crosstab_data.plot(kind='bar', stacked=True, figsize=(10, 6), colormap='viridis')
plt.title('Distribución de Descuentos por Categoría de Producto')
plt.xlabel('Categoría')
plt.ylabel('Número de Productos')
plt.xticks(rotation=45, ha='right')
plt.legend(title='Con Descuento', labels=['No', 'Sí'])
plt.show()

🗓️ Análisis de Series Temporales (cuando aplica)

Si tu dataset tiene una columna de fecha/tiempo, como Fecha_Venta, es crucial analizar su comportamiento a lo largo del tiempo. Pandas facilita esto enormemente.

# Calcular el valor total de la venta por fecha
df_cleaned['Valor_Venta_Total'] = df_cleaned['Precio'] * df_cleaned['Cantidad_Vendida']

# Agrupar por fecha para ver tendencias diarias
daily_sales = df_cleaned.groupby('Fecha_Venta')['Valor_Venta_Total'].sum().reset_index()

plt.figure(figsize=(12, 6))
sns.lineplot(data=daily_sales, x='Fecha_Venta', y='Valor_Venta_Total', marker='o', color='#6C5CE7')
plt.title('Tendencia de Ventas Diarias')
plt.xlabel('Fecha')
plt.ylabel('Valor Total de Ventas')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()

🧠 Paso 5: Ingeniería de Características (Feature Engineering)

A veces, las variables existentes no son suficientes para capturar toda la información. La ingeniería de características es el proceso de crear nuevas variables a partir de las existentes que puedan ser más útiles para tu análisis o modelo.

# Ejemplo: Crear una columna 'Mes' a partir de 'Fecha_Venta'
df_cleaned['Mes_Venta'] = df_cleaned['Fecha_Venta'].dt.month_name()

# Crear una columna 'Precio_por_Unidad_Promedio_Categoria' (ejemplo más complejo)
mean_price_per_category = df_cleaned.groupby('Categoria')['Precio'].mean().reset_index()
mean_price_per_category.rename(columns={'Precio': 'Precio_Promedio_Categoria'}, inplace=True)

df_cleaned = pd.merge(df_cleaned, mean_price_per_category, on='Categoria', how='left')

print("\nDataFrame con nuevas características:\n")
print(df_cleaned[['Fecha_Venta', 'Mes_Venta', 'Categoria', 'Precio', 'Precio_Promedio_Categoria']].head())

# Visualizar ventas por mes
monthly_sales = df_cleaned.groupby('Mes_Venta')['Valor_Venta_Total'].sum().reindex(
    ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
).fillna(0).reset_index()

plt.figure(figsize=(10, 6))
sns.barplot(data=monthly_sales, x='Mes_Venta', y='Valor_Venta_Total', palette='viridis')
plt.title('Ventas Totales por Mes')
plt.xlabel('Mes')
plt.ylabel('Valor Total de Ventas')
plt.xticks(rotation=45, ha='right')
plt.tight_layout()
plt.show()

📊 Diagrama de Flujo del Proceso EDA

Para resumir el proceso, aquí tienes un diagrama de flujo simple que ilustra los pasos clave del EDA:

INICIO (Carga de Datos) Inspección Inicial Limpieza de Datos ¿Hay Problemas? No Análisis Univariado Análisis Bivariado/Multivariado Visualización y Reporte FIN (Listo para Modelado)

--- 

## ✅ Conclusión

Has completado un viaje exhaustivo a través del Análisis Exploratorio de Datos con Pandas y NumPy. Desde la carga inicial hasta la visualización y la ingeniería de características, ahora tienes las herramientas y la comprensión para abordar cualquier conjunto de datos. Recuerda que el EDA no es solo una fase; es una mentalidad de curiosidad y escepticismo saludable que te permitirá entender tus datos a un nivel profundo.

El dominio del EDA te diferenciará como científico de datos, permitiéndote tomar decisiones informadas, identificar problemas potenciales antes de que se conviertan en errores costosos y, en última instancia, construir modelos más robustos y significativos.

<div class="callout tip">💡 <strong>Consejo Final:</strong> Practica con diferentes conjuntos de datos. Kaggle es un excelente recurso para encontrar datasets y notebooks de EDA de otros para aprender.</div>

¡Sigue explorando y desvelando los secretos de tus datos! 🚀

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!