Limpieza de datos con Python
Cuando trabajamos con datos podemos hacer uso de una metodología muy conocida denominada CRISP-DM (Cross Industry Standard Process for Data Mining) donde se describe el ciclo de vida de un proyecto de datos, cada una de sus etapas cumple con un objetivo y busca alinear las metas de negocio con la información que se tiene.
1. Entendimiento del negocio: Determinar los objetivos del negocio, cuáles son sus necesidades y lo que se desea abarcar.
2. Entendimiento de los datos: De acuerdo a la fase anterior, con que datos cuento, que datos son útiles y cuáles necesito.
3. Preparación de datos: En esta fase se exploran los datos, se manipulan y se limpian, se hace la unión entre lo que quiere/necesita el negocio con los datos con los que cuenta la organización
4. Modelamiento: Teniendo en cuenta los puntos anteriores se realiza el análisis y se obtienen resultados.
5. Evaluación: Una vez se obtienen los resultados se evalúa el modelo teniendo en cuenta el objetivo del análisis
6. Despliegue: Una vez validado el modelo se realiza la implementación en producción, así como monitoreo y mantenimiento.
Una de las etapas donde los científicos y analistas de datos usan más tiempo es la preparación de datos, donde se valida la información, se hacen modificaciones o adiciones necesarias que ayuden a cumplir con el objetivo del negocio y una vez esté listo se pasa a la etapa de modelos. En esta ocasión nos enfocaremos en la fase de preparación de datos, en especifico limpieza de datos. Este es un resumen breve de como funciona la metodología y cada una de sus etapas, si quieres saber más sobre CRISP-DM ingresa aquí.
Limpieza de datos
En esta etapa realizamos exploración de datos y detección de datos inválidos, para realizar la corrección y/o eliminación. Este proceso consta de reemplazar datos nulos o inválidos, cambiar tipos de variables, cambiar escalas de los datos, eliminar datos innecesarios y crear nuevas columnas. Pero, por qué es necesario realizar esta limpieza?
Cuando accedemos a los datos se realiza una exploración y análisis de los mismos, esto con el objetivo de validar si los datos se alinean con los objetivos de negocio y nos ayudan a comprender el panorama que tenemos, se pueden realizar análisis descriptivos donde con ayuda de los datos podemos determinar que está sucediendo y a partir de allí tomar decisiones, luego de esto se generan modelos y reportes, si los datos desde un inicio están mal todo el proceso que sigue estará afectado por la calidad de la información que tenemos, lo que nos lleva a tener resultados que no estén muy alineados con lo que estamos buscando.
En esta guía usaremos Python y algunas de sus librerías para realizar limpieza de datos:
- Pandas: Es una librería de código abierto de Python, especializada en el manejo y análisis de estructuras de datos.
- Datetime: Proporciona clases para manipular fechas y horas.
- Missingno: Es una librería que permite visualizar la distribución de valores nulos.
- Fuzzywuzzy: Permite calcular las diferencias entre dos secuencias.
- Recordlinkage: Permite unir dos o más registros que pertenecen a la misma entidad.
#Importar librerías
import pandas as pd
import datetime as dt
import missingno as msno
import fuzzywuzzy
import recordlinkage
Ahora si, ¡manos a la obra!
Tipos de datos
En Python tenemos diferentes tipos de datos:
- Texto: str
- Entero: int
- Decimal: float
- Binario: bool
- Fecha y hora: datetime
- Categórico: category
Para validar el tipo de dato en Python podemos usar dtypes:
df.dtypes
Este nos permite visualizar las columnas del dataframe y los tipos de datos de cada una de ellas, de esta forma validamos si los tipos de datos son correctos o se debe hacer un cambio.
Para cambiar el tipo de dato usamos astype():
df['<nombre_columna>'].astype(‘<tipo_dato>’)
En el tipo_dato especificamos uno de los tipos de datos mencionados anteriormente, por ejemplo, int para cambiarlo a entero.
Si una columna tiene un tipo de dato incorrecto debido a que contiene un carácter, lo podemos eliminar de la siguiente manera:
df['<nombre_columna>'] = df['<nombre_columna>'].str.strip('<carácter>')
Con str convertimos a texto (string) cada unas de las filas para la columna seleccionada y con strip() eliminamos el carácter que se especifique entre paréntesis.
Valores no permitidos
Cuando tenemos columnas con fechas se recomienda hacer una validación de las fechas existentes para verificar que estas no sean mayores a la fecha actual o ultima fecha donde se tomaron los datos. Para ello usamos la librería datetime:
fecha_actual = dt.date.today()#Validar si hay fechas mayores a la actual
df[df['fecha']>fecha_actual]
Si existen fechas mayores podemos reemplazarlos o eliminarlos:
#Dejar solo los valores validos
df = df[df['fecha'] < fecha_actual] #Reemplazar valores
df.loc[df['fecha'] > fecha_actual, 'fecha'] = fecha_actual#Eliminar valores
df.drop(df[df['fecha'] > fecha_actual].index, inplace = True)
Manejo de fechas
Al leer y crear un dataframe desde un archivo .csv o cualquier fuente la columna que contiene fecha y hora se encuentra como tipo de dato object (texto). Para convertirlo datetime usamos la siguientes línea:
datetime.strptime(df['<columna_fechas>'], <formato>)
En la librería datetime usamos el método datetime.strptime(), como primer parámetro le pasamos la columna o cadena de caracteres que contiene la fecha, y como segundo parámetro le pasamos el tipo de formato que queremos para la fecha, por ejemplo, “%Y/%m/%d”. En este enlace podrás encontrar más formatos y como usarlos.
En ocasiones solo necesitamos el año o mes de la fecha para procesar y evaluar los datos, para ello la librería datetime nos brinda algunas herramientas para manejo de fechas y horas:
#Si la columna es tipo dato datetime
df['año'] = df['fecha'].dt.year #Obtener año
df['mes'] = df['fecha'].dt.month #Obtener mes
En el enlace podrás encontrar otras opciones para extraer la información necesaria de la fecha.
Valores duplicados
Hay varias razones por las cuales podemos tener valores duplicados en nuestro dataframe, pueden ser errores humanos al ingresar los datos, bugs o errores de diseño o cuando realizamos una unión de bases de datos.
Para validar si tenemos valores duplicados usamos duplicated():
df[df.duplicated()]
El método duplicated() tiene dos parámetros:
- subset: Especificar las columnas donde queremos comparar las datos para validar si existen duplicados.
- keep: Indicar que valor queremos mantener ‘first’ (primero), ‘last’ (ultimo) o False (todos).
df[df.duplicated(subset = [<nombres_columnas>], keep = False)]
Para eliminar valores duplicados usamos el método drop_duplicates() con un parámetro adicional inplace y le asignamos el valor True:
df.drop_duplicates(inplace = True)
Inplace nos permite realizar los cambios en el dataframe de forma permanente.
Variables categóricas
Para las variable categóricas tenemos opciones o valores definidos que pueden tomar estas variables, sin embargo, podemos ingresar datos con pequeñas diferencias como espacios, valores no definidos, uso de mayúsculas y minúsculas. Para solucionar estos inconvenientes podemos mapear los valores para que queden con una única clasificación.
Valores no definidos:
Para hallar inconsistencias en las categorías antes de unir dos o mas fuentes de datos usamos el método difference():
inconsistentes = set(df1['<nombre_columna>']).difference(df2['<nombre_columna>'])
El código anterior nos muestra los datos de df1 que no hacen parte de df2. set() nos permite tener una secuencia con datos únicos para la columna indicada, con ello comparamos mediante difference() los datos inconsistentes. Por lo general, df2 corresponde a los valores que puede tomar la variable y que están definidas en el diccionario de datos.
Para validar la posición donde se encuentran los valores inconsistentes usamos el método isin() que nos permite identificar si los valores de una columna corresponden a los valores indicados en isin.
inconsistencia = df[df['<columna>'].isin(inconsistentes)]
Para eliminar datos inconsistentes podemos filtrar nuestro dataframe y tomar los valores que no corresponden a la lista de valores definidos previamente como inconsistentes:
df[~inconsistencia]
Valores con nombre diferente e igual significado:
Para validar los valores que tiene una columna podemos usar unique():
#Valores únicos
df['<columna>'].unique()#Valores únicos y su frecuencia
df['<columna>'].value_counts()
Si las diferencias de nombres son por combinaciones de mayúsculas y minúsculas:
df['<columna>'] = df['<columna>'].str.lower() #Pasar a minúsculas
df['<columna>'] = df['<columna>'].str.upper() #Pasar a mayúsculas
Si las diferencias son por espacios:
df['<columna>'].str.strip() #Eliminar espacios
Crear categorías a partir de valores numéricos:
Pandas tiene la función cut() que nos permite crear categorías a partir de valores continuos:
df['<columna_categorias>'] = pd.cut(df['<columna_numeros>'], bins= <rango_divisiones>,labels = <nombres_divisiones>)
Crear categorías a partir de variables tipo texto:
Con el método replace() podemos cambiar el valor de texto a categorías definidas que agrupen esos valores:
df['<columna>'] = df['<columna>'].replace({<valor_anterior>:<valor_nuevo>})
Reemplazar caracteres:
Podemos reemplazar un carácter usando el método replace():
df['<columna>'].str.replace("<caracter_existente>","<caracter_nuevo>")
Expresiones regulares
Las expresiones regulares son muy útiles para encontrar patrones en una cadena de caracteres, para hacer uso de estas debemos importar la librería re:
import re
phones['<Phone_number>'].str.replace(r'\D+', '') #Eliminar el símbolo '+' al inicio de un numero telefónico
Asimismo, si queremos encontrar una cadena de texto que coincida con un patrón indicado:
import re
match = re.search(<patron>,<texto>)
match.start()
match.end()
- search() permite buscar en todo el texto si existe coincidencia.
- start() y end() devuelven la posición de inicio y fin respectivamente para la coincidencia.
Esta librería nos muestra diferentes herramientas para encontrar coincidencia con patrones en el texto:
Aquí puedes encontrar más información sobre que son las expresiones regulares y como usarlas.
Los datos son información muy valiosa para una organización pero por si solos no nos aportan mucho, debemos entenderlos y analizarlos, si tenemos muchos datos pero son inválidos de nada nos servirán si queremos hacer análisis descriptivos o implementación de modelos de machine learning o deep learning. Los buenos resultados dependerán de la calidad de nuestros datos, por esta razón se hace tan importe realizar una limpieza de datos adecuada.
Ahora veamos estos pasos en acción con un ejercicio práctico de limpieza de datos:
https://github.com/SandyAtencio/Cleaning_data_Python_Part_1
Esta publicación está basada en el curso Cleaning Data in Python de Datacamp, super recomendado. Si apenas estás iniciando en el campo de los datos te recomiendo leer la publicación Guía práctica para análisis exploratorio de datos con Pandas, en la cual vas a encontrar una guía para explorar tu dataframe y conocer los datos que tienes para su posterior limpieza.
En esta ocasión realicé una colaboración con Sandy Atencio, ella es ingeniera de sistemas y científica de datos en formación, apasionada por los datos, le gusta compartir conocimiento en comunidades, entusiasta por la incorporación de más mujeres en STEM, amante a los girasoles y creyente de la frase: “el Feedback nos hace crecer”. Aquí les dejo su blog donde en los próximos días podrán encontrar la segunda parte de limpieza de datos con Python.