Manipulación, Limpieza y Exploración de Datos

Manipulación, Limpieza y Exploración de Datos#

Este cuaderno tiene como objetivo revisar diversas técnicas de manipulación y limpieza de datos. Posterior al procesamiento de datos, realizaremos un análisis exploratorio de los datos para obtener insights valiosos. Es importante tener en cuenta que usaremos el dataset bank_marketing del repositorio de Machine Learning de UCI. Este conjunto de datos nos proporcionará una gran oportunidad para aplicar y practicar las técnicas que aprenderemos.

Contenidos#

A lo largo de este cuaderno, abordaremos los siguientes temas:

  • Selección y filtrado de datos: Aprenderemos cómo seleccionar y filtrar datos de manera eficiente en Python.

  • Manejo de valores nulos: Trataremos con valores nulos y aprenderemos técnicas para manejarlos.

  • Transformación de columnas: Veremos cómo transformar y manipular columnas en un DataFrame.

  • Estadísticas descriptivas: Obtendremos estadísticas descriptivas de nuestros datos para entender mejor su distribución y tendencias.

  • Correlaciones: Exploraremos las correlaciones entre diferentes variables en nuestros datos.

Ejemplos prácticos#

Aplicaremos estas técnicas en ejemplos prácticos para mejorar la calidad de los datos y para identificar tendencias y patrones en datos de ventas y marketing.

Dataset#

Para este cuaderno, utilizaremos el dataset bank_marketing del repositorio de Machine Learning de UCI. Este conjunto de datos nos proporcionará una gran oportunidad para aplicar y practicar las técnicas que aprenderemos.

## Carga de datos

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


data=pd.read_csv('bank_marketing.csv')

# Mostrar las primeras filas
display(data.head())

# Información general del DataFrame
display(data.info())
age job marital education default balance housing loan contact day_of_week month duration campaign pdays previous poutcome HasTermDeposit
0 58 management married tertiary no 2143 yes no NaN 5 may 261 1 -1 0 NaN no
1 44 technician single secondary no 29 yes no NaN 5 may 151 1 -1 0 NaN no
2 33 entrepreneur married secondary no 2 yes yes NaN 5 may 76 1 -1 0 NaN no
3 47 blue-collar married NaN no 1506 yes no NaN 5 may 92 1 -1 0 NaN no
4 33 NaN single NaN no 1 no no NaN 5 may 198 1 -1 0 NaN no
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 45211 entries, 0 to 45210
Data columns (total 17 columns):
 #   Column          Non-Null Count  Dtype 
---  ------          --------------  ----- 
 0   age             45211 non-null  int64 
 1   job             44923 non-null  object
 2   marital         45211 non-null  object
 3   education       43354 non-null  object
 4   default         45211 non-null  object
 5   balance         45211 non-null  int64 
 6   housing         45211 non-null  object
 7   loan            45211 non-null  object
 8   contact         32191 non-null  object
 9   day_of_week     45211 non-null  int64 
 10  month           45211 non-null  object
 11  duration        45211 non-null  int64 
 12  campaign        45211 non-null  int64 
 13  pdays           45211 non-null  int64 
 14  previous        45211 non-null  int64 
 15  poutcome        8252 non-null   object
 16  HasTermDeposit  45211 non-null  object
dtypes: int64(7), object(10)
memory usage: 5.9+ MB
None

Limpieza de datos#

La limpieza de datos es un paso crucial en el proceso de análisis de datos. Los datos limpios son esenciales para obtener resultados precisos y confiables. En esta sección, aprenderemos a limpiar y manipular datos utilizando Python y la biblioteca Pandas.

Note

Pandas es una biblioteca de Python que proporciona estructuras de datos y herramientas de análisis de datos. Es ampliamente utilizada en la comunidad de ciencia de datos y es una de las bibliotecas más populares para el análisis de datos en Python.

Para el proceso de limpieza y manipulación de datos, utilizaremos las siguientes funciones y métodos de Pandas:

  • isnull(): Comprueba si hay valores nulos en un DataFrame.

  • dropna(): Elimina filas o columnas con valores nulos de un DataFrame.

  • fillna(): Rellena los valores nulos con un valor específico.

  • astype(): Convierte el tipo de datos de una columna a un tipo de datos específico.

  • describe(): Muestra estadísticas descriptivas de un DataFrame.

  • corr(): Calcula la correlación entre columnas de un DataFrame.

  • plot(): Crea gráficos a partir de los datos de un DataFrame.

  • value_counts(): Cuenta los valores únicos en una columna de un DataFrame.

# Identificar valores faltantes
display(data.isnull().sum())

# Si hay valores faltantes, aplicar estrategias de imputación o eliminación
age                   0
job                 288
marital               0
education          1857
default               0
balance               0
housing               0
loan                  0
contact           13020
day_of_week           0
month                 0
duration              0
campaign              0
pdays                 0
previous              0
poutcome          36959
HasTermDeposit        0
dtype: int64
## Variable job

data['job'].value_counts(dropna=False)
job
blue-collar      9732
management       9458
technician       7597
admin.           5171
services         4154
retired          2264
self-employed    1579
entrepreneur     1487
unemployed       1303
housemaid        1240
student           938
NaN               288
Name: count, dtype: int64
## Estrategias de imputación

# Imputación con la moda

data_1=data.copy()
data_1['job'].fillna(data_1['job'].mode()[0], inplace=True)

# Imputación con la categoría 'Desconocido'

data_2=data.copy()
data_2['job'].fillna('Desconocido', inplace=True)


# Eliminación de las filas con valores faltantes

data_3=data.copy()
data_3.dropna(subset=['job'], inplace=True)

# Comparación de las estrategias de imputación

print(data['job'].value_counts(dropna=False))

print(data_1['job'].value_counts(dropna=False))

print(data_2['job'].value_counts(dropna=False))

print(data_3['job'].value_counts(dropna=False))
job
blue-collar      9732
management       9458
technician       7597
admin.           5171
services         4154
retired          2264
self-employed    1579
entrepreneur     1487
unemployed       1303
housemaid        1240
student           938
NaN               288
Name: count, dtype: int64
job
blue-collar      10020
management        9458
technician        7597
admin.            5171
services          4154
retired           2264
self-employed     1579
entrepreneur      1487
unemployed        1303
housemaid         1240
student            938
Name: count, dtype: int64
job
blue-collar      9732
management       9458
technician       7597
admin.           5171
services         4154
retired          2264
self-employed    1579
entrepreneur     1487
unemployed       1303
housemaid        1240
student           938
Desconocido       288
Name: count, dtype: int64
job
blue-collar      9732
management       9458
technician       7597
admin.           5171
services         4154
retired          2264
self-employed    1579
entrepreneur     1487
unemployed       1303
housemaid        1240
student           938
Name: count, dtype: int64
## Tratamiento de variables nulas numéricas

Ejemplo=pd.DataFrame({'A':[1,2,None,None,3,4,None,5,6,None,7,8,None,9,10,None],})
Ejemplo
A
0 1.0
1 2.0
2 NaN
3 NaN
4 3.0
5 4.0
6 NaN
7 5.0
8 6.0
9 NaN
10 7.0
11 8.0
12 NaN
13 9.0
14 10.0
15 NaN
## Imputación con la media

Ejemplo_1=Ejemplo.copy()
Ejemplo_1['A'].fillna(Ejemplo_1['A'].mean(), inplace=True)
Ejemplo_1
A
0 1.0
1 2.0
2 5.5
3 5.5
4 3.0
5 4.0
6 5.5
7 5.0
8 6.0
9 5.5
10 7.0
11 8.0
12 5.5
13 9.0
14 10.0
15 5.5
## Imputación con la mediana

Ejemplo_2=Ejemplo.copy()
Ejemplo_2['A'].fillna(Ejemplo_2['A'].median(), inplace=True)
Ejemplo_2
A
0 1.0
1 2.0
2 5.5
3 5.5
4 3.0
5 4.0
6 5.5
7 5.0
8 6.0
9 5.5
10 7.0
11 8.0
12 5.5
13 9.0
14 10.0
15 5.5
## Imputación con la moda

Ejemplo_3=Ejemplo.copy()
Ejemplo_3['A'].fillna(Ejemplo_3['A'].mode()[0], inplace=True)
Ejemplo_3
A
0 1.0
1 2.0
2 1.0
3 1.0
4 3.0
5 4.0
6 1.0
7 5.0
8 6.0
9 1.0
10 7.0
11 8.0
12 1.0
13 9.0
14 10.0
15 1.0
## Imputación con un valor constante

Ejemplo_4=Ejemplo.copy()
Ejemplo_4['A'].fillna(-999, inplace=True)
Ejemplo_4
A
0 1.0
1 2.0
2 -999.0
3 -999.0
4 3.0
5 4.0
6 -999.0
7 5.0
8 6.0
9 -999.0
10 7.0
11 8.0
12 -999.0
13 9.0
14 10.0
15 -999.0
## Eliminación de las filas con valores faltantes

Ejemplo_5=Ejemplo.copy()
Ejemplo_5.dropna(subset=['A'], inplace=True)
Ejemplo_5
A
0 1.0
1 2.0
4 3.0
5 4.0
7 5.0
8 6.0
10 7.0
11 8.0
13 9.0
14 10.0

Corrección de tipos de datos#

El primer paso en el proceso de limpieza de datos es corregir los tipos de datos. A menudo, los datos se almacenan en formatos que no son adecuados para el análisis. Por ejemplo, una columna que debería ser numérica se almacena como una cadena. En esta sección, aprenderemos a corregir los tipos de datos de un DataFrame.

Note

Para corregir los tipos de datos de un DataFrame, utilizaremos el método astype() de Pandas. Este método nos permite convertir el tipo de datos de una columna a un tipo de datos específico. Por ejemplo, si queremos convertir una columna a un tipo de datos numérico, podemos usar el siguiente código:

df['column_name'] = df['column_name'].astype('float')
## Variable day_of_month

data['day_of_month'].value_counts(dropna=False)
data['month'].value_counts(dropna=False)
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
File ~\miniconda3\Lib\site-packages\pandas\core\indexes\base.py:3790, in Index.get_loc(self, key)
   3789 try:
-> 3790     return self._engine.get_loc(casted_key)
   3791 except KeyError as err:

File index.pyx:152, in pandas._libs.index.IndexEngine.get_loc()

File index.pyx:181, in pandas._libs.index.IndexEngine.get_loc()

File pandas\_libs\hashtable_class_helper.pxi:7080, in pandas._libs.hashtable.PyObjectHashTable.get_item()

File pandas\_libs\hashtable_class_helper.pxi:7088, in pandas._libs.hashtable.PyObjectHashTable.get_item()

KeyError: 'day_of_month'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
Cell In[12], line 3
      1 ## Variable day_of_month
----> 3 data['day_of_month'].value_counts(dropna=False)
      4 data['month'].value_counts(dropna=False)

File ~\miniconda3\Lib\site-packages\pandas\core\frame.py:3893, in DataFrame.__getitem__(self, key)
   3891 if self.columns.nlevels > 1:
   3892     return self._getitem_multilevel(key)
-> 3893 indexer = self.columns.get_loc(key)
   3894 if is_integer(indexer):
   3895     indexer = [indexer]

File ~\miniconda3\Lib\site-packages\pandas\core\indexes\base.py:3797, in Index.get_loc(self, key)
   3792     if isinstance(casted_key, slice) or (
   3793         isinstance(casted_key, abc.Iterable)
   3794         and any(isinstance(x, slice) for x in casted_key)
   3795     ):
   3796         raise InvalidIndexError(key)
-> 3797     raise KeyError(key) from err
   3798 except TypeError:
   3799     # If we have a listlike key, _check_indexing_error will raise
   3800     #  InvalidIndexError. Otherwise we fall through and re-raise
   3801     #  the TypeError.
   3802     self._check_indexing_error(key)

KeyError: 'day_of_month'
### Hagamos una cadena de texto de la forma dd-mmm
## debemos cambiar el tipo de dato de day_of_month como una cadena de texto (string)

data['day_of_month']=data['day_of_month'].astype(str)
data['day_of_month']
0         5
1         5
2         5
3         5
4         5
         ..
45206    17
45207    17
45208    17
45209    17
45210    17
Name: day_of_month, Length: 45211, dtype: object
## Creamos la variable day_month

data['day_month']=data['day_of_month']+'-'+data['month']+'-2023'

data['day_month']
0         5-may-2023
1         5-may-2023
2         5-may-2023
3         5-may-2023
4         5-may-2023
            ...     
45206    17-nov-2023
45207    17-nov-2023
45208    17-nov-2023
45209    17-nov-2023
45210    17-nov-2023
Name: day_month, Length: 45211, dtype: object
## La convertimos a tipo de dato fecha

data['day_month']=pd.to_datetime(data['day_month'], format='%d-%b-%Y')
data['day_month']
0       2023-05-05
1       2023-05-05
2       2023-05-05
3       2023-05-05
4       2023-05-05
           ...    
45206   2023-11-17
45207   2023-11-17
45208   2023-11-17
45209   2023-11-17
45210   2023-11-17
Name: day_month, Length: 45211, dtype: datetime64[ns]
### Cambiar el tipo de dato trae sus ventajas
from datetime import datetime

today=datetime.now()

data['days_to_today']=(today-data['day_month']).dt.days
data['days_to_today']
0        298
1        298
2        298
3        298
4        298
        ... 
45206    102
45207    102
45208    102
45209    102
45210    102
Name: days_to_today, Length: 45211, dtype: int64