Limpieza de datos: preparación de los datos para su uso
Al finalizar este tema
Podrás identificar y solucionar problemas comunes en los datos reales, como los valores faltantes, los duplicados y los valores atípicos.
¿Por qué es necesaria la limpieza de datos?
Los datos del mundo real no siempre son perfectos. Pueden tener respuestas incompletas en las encuestas, entradas duplicadas de la misma persona o incluso filas con edades negativas, como -5 años. Analizar estos datos sin procesarlos puede generar resultados poco fiables.
Se estima que entre el 60 y el 80 % del trabajo de análisis de datos se dedica a la limpieza. Esta etapa es mucho más importante que aplicar técnicas de análisis sofisticadas.
Paso 1: Obtener una visión general de los datos
import pandas as pd
df = pd.read_csv("patients.csv")
# Información básicaprint(df.shape) # (1000, 8) — 1000 filas, 8 columnasprint(df.dtypes) # Tipo de datos de cada columnaprint(df.info()) # Resumen que incluye estado de valores faltantes
# Verificar inicio/finalprint(df.head()) # Primeras 5 filasprint(df.tail()) # Últimas 5 filas
# Resumen estadísticoprint(df.describe()) # Media, desviación estándar, mínimo/máximo de columnas numéricas, etc.Al ejecutar df.info(), se muestra el recuento de valores no nulos. Si este recuento es menor que el número total de filas, significa que hay valores faltantes. En df.describe(), si los valores mínimo y máximo están fuera de un rango razonable, se deben investigar posibles valores atípicos.
Paso 2: Manejo de valores faltantes
# Verificar valores faltantesprint(df.isnull().sum())# name 0# age 15# blood_type 3# weight 42
# Estrategia 1: Eliminar — cuando las filas con valores faltantes son minoríadf_clean = df.dropna(subset=["blood_type"]) # Elimina 3 filas sin blood_type
# Estrategia 2: Rellenar — columnas numéricasdf["age"] = df["age"].fillna(df["age"].median()) # Con la medianadf["weight"] = df["weight"].fillna(df["weight"].mean()) # Con la media
# Estrategia 3: Rellenar con un valor específicodf["blood_type"] = df["blood_type"].fillna("Desconocido")La estrategia a utilizar depende del contexto.
- Si la proporción de valores faltantes es inferior al 5 %, la opción más segura es eliminarlos.
- Para las variables numéricas, se imputan con la mediana (robusta frente a los valores atípicos) o la media.
- Para las variables categóricas (tipo de sangre, género), se imputan con la moda o con la opción "no especificado".
Paso 3: Eliminación de duplicados
# Verificar duplicadosprint(df.duplicated().sum()) # 23 filas duplicadas
# Ver contenido de los duplicadosprint(df[df.duplicated(keep=False)]) # Muestra tanto el original como los duplicados
# Eliminar duplicados (conservar la primera aparición)df = df.drop_duplicates()
# Eliminación de duplicados por columna específicadf = df.drop_duplicates(subset=["patient_id"], keep="last")keep="first" conserva la primera fila y elimina las demás. keep="last" conserva la última. Si los datos están ordenados cronológicamente, last conserva el registro más reciente.
Paso 4: Detección de valores atípicos
# Verificar con estadísticas básicasprint(df["age"].describe())# min: -5 ← anómalo# max: 200 ← anómalo
# Filtrado por rangodf = df[(df["age"] >= 0) & (df["age"] <= 120)]
# Método IQR — detección estadística de valores atípicosQ1 = df["weight"].quantile(0.25)Q3 = df["weight"].quantile(0.75)IQR = Q3 - Q1lower = Q1 - 1.5 * IQRupper = Q3 + 1.5 * IQR
outliers = df[(df["weight"] < lower) | (df["weight"] > upper)]print(f"Se encontraron {len(outliers)} valores atípicos")
# Eliminación de valores atípicosdf = df[(df["weight"] >= lower) & (df["weight"] <= upper)]No se deben eliminar los valores atípicos sin más. Si bien una edad de -5 es un error evidente que debe eliminarse, un peso de 150 kg podría ser un valor real. El conocimiento del dominio es clave para determinar qué se considera un valor atípico.
Paso 5: Conversión de tipos y unificación de formatos
# Números como cadenas → tipo numéricodf["age"] = pd.to_numeric(df["age"], errors="coerce")
# Cadenas de fecha → datetimedf["visit_date"] = pd.to_datetime(df["visit_date"])
# Limpieza de cadenas: eliminar espacios iniciales/finales y unificar mayúsculas/minúsculasdf["name"] = df["name"].str.strip()df["blood_type"] = df["blood_type"].str.upper()errors="coerce" procesa los valores no convertibles (por ejemplo, "N/A") como NaN. Esto resulta útil para grandes conjuntos de datos, ya que permite continuar el proceso sin generar errores.
Resumen clave
| Paso | Aspecto a verificar | Herramientas principales |
|---|---|---|
| Visión general | Número de filas/columnas, tipos de datos, estado de los valores faltantes | info(), describe() |
| Valores faltantes | Verificar la proporción → eliminar o imputar | isnull(), fillna(), dropna() |
| Duplicados | Filas idénticas o duplicados según una clave | duplicated(), drop_duplicates() |
| Valores atípicos | Rango razonable + IQR | describe(), filtrado por rango |
| Tipos/formato | Unificar números, fechas y cadenas de texto | to_numeric(), to_datetime(), str.strip() |
La limpieza de datos es una tarea repetitiva y tediosa, pero omitir este paso comprometerá todos los resultados del análisis posterior. "Garbage in, garbage out": si la entrada es incorrecta, la salida también lo será.