Data Cleaning con Pandas. Parte 2.

Patricia Carmona
Ironhack
Published in
6 min readFeb 18, 2020
Photo by Michael Payne on Unsplash

Ésta es la segunda parte de Data Cleaning. En este artículo vas a encontrar métodos avanzados para el Data Cleaning. En la primera parte, puedes ver una recopilación de métodos para filtrar el DataFrame seleccionando series, explorar valores duplicados y nulos y un filtrado aplicando una condición.

En este post continúo con la exploración del DataFrame que monté usando el dataset de Shark Attacks de Kaggle. Este DataFrame está filtrado a columnas que son útiles para probar la hipótesis de que el mayor número de ataques a surfistas se produjo en la costa oeste de Estados Unidos y a la actividad surf, reduciendo el tamaño y el ámbito de la información del DataFrame.

Agrupación y agregación de información

Para resumir la información del DataFrame, la agrupación es tu mejor aliado. El método .groupby() genera grupos en base a una o varias series.

Para agrupar puedes crear un nuevo DataFrame o puedes agrupar sobre el mismo, aplicando diferentes métodos. Te muestro cómo es la agrupación por países:

df.groupby(['Country'])                # Agrupa por países
df.groupby(['Country']).get_first() # Muestra el primer registro
df.groupby(['Country']).get_group('USA') # Muestra el grupo USA
DataFame agrupa por país, seleccionando el grupo USA

Para agrupar por país y área, solo tienes que indicar ambas series en el método. A continuación te muestro un resumen de la agrupación país y área.

df.groupby(['Country', 'Area']).count()
Conteo de registros por país y área

La sintaxis de .groupby() indica entre paréntesis las series que quieres agrupar y después, puedes seleccionar una serie entre corchetes para aplicar un método básico estadístico de pandas como .sum(), .count(), .max(), .min(), .mean(), .median() o .mode().

Junto con el método .groupby() es muy frecuente aplicar el método de agregación .agg() que permite aplicar una o varias funciones a una o más series.

Binning: un paso más en la agrupación

La agrupación y segmentación de datos puede ser más exhaustiva con pandas. No tiene que ceñirse solo a un filtro de una serie, sino que puede obtener diferentes grupos dentro de una misma serie. Por ejemplo, en una serie donde se muestre el año, puedes crear bins por décadas o puedes crear bins para agrupar edades en un DataFrame.

Para hacer esta agrupación se utiliza el método .cut() que facilita hacer esos “cortes” y agrupar.

Filtrando el DataFrame por los últimos 30 años, genero bins por décadas y los guardo en una nueva columna.

df['Decada'] = pd.cut(df.Year,4, labels=range(1980,2020,10))
La nueva serie Década

De esta forma podemos crear nuevas series y agrupar la información de una forma más útil y flexible.

El tipo de datos que necesitas

En algunas ocasiones, las series numéricas se comportan como string en lugar de como series de números enteros o decimales. Para este tipo de casos, en los que necesites operar con los valores de una serie pero pandas los interpreta como string, hay que castear los valores indicando qué tipo de dato tienen que ser. Puedes conocer el tipo de dato con el método .dtypes() y castear con el método .astype(), indicando entre paréntesis el formato.

df.dtypes                            # Conocer el tipo de datos
df['Case Number'].astype() # Castear

Para que pandas interprete una serie de fechas como formato ‘datetime64’ te recomiendo utilizar el método .to_datetime(serie a castear) siempre que la serie tenga el mismo formato numérico que un timestamp. En el caso de este DataFrame hay algunos registros cuya fecha se indica en otro formato, por lo que devuelve un error.

Trabajar con fechas

Una de las maravillas de pandas es la versatilidad de trabajo con fechas y con la clase Timestamp. Si tienes una serie que contiene una fecha y pandas la trata como tal o la has casteado al formato ‘datetime64’, existen varias posibilidades para extraer el año, el mes o el día y utilizarlo como filtro o como nueva serie en el DataFrame.

df.Date.dt.year                     # Extraer el año
df.Date.dt.month # Extraer el mes
df.Date.dt.day # Extraer el día
# Crear la serie Month extrayendo el mes de la serie Datedf['Month'] = df.Date.df.Date.dt.month

También puedes utilizar los métodos .dt.hour(), .dt.minute() y .dt.second(). Es una forma de fragmentar una serie muy útil ya que el filtro de fecha es uno de los más utilizados.

Trabajar con el contenido

No siempre los datos de una columna de fecha siguen el estándar datetime o no todos tienen el mismo formato. En ocasiones, una serie contiene strings de los que necesitas extraer una parte concreta. Para todo lo que cumpla un patrón y no pueda buscarse con métodos que ya están integrados, pandas trabaja con Regex.

Regex son expresiones regulares que automatizan la búsqueda de un patrón en una cadena de texto (string). Las expresiones regulares no son inherentes a pandas o Python, si no que se utilizan en muchos lenguajes y ahorran mucho tiempo buscando de forma manual.

Ordenar valores

A veces la búsqueda y el trabajo con la información es mucho más cómodo si esa información está ordenada. El método .sort_values() permite ordenar un DataFrame en base a una o varias series, a continuación te muestro cómo ordené el DataFrame en base al año en el que había sucedido el ataque.

df.sort_values('Year', ascending=True)
Filtrando desde 1980, ordenado de forma ascendente

Trabajo final para probar la hipótesis del estudio

Buena parte de los métodos y técnicas de este post no los llevé a la práctica en el análisis del ataque de tiburones, pero quiero dejar constancia de cómo cerré la prueba de la hipótesis.

Una vez filtrado el DataFrame por la actividad Surfing, tras buscar en diferentes series si había alguna posibilidad para completar los registros nulos de Actividad, hice un conteo del número de ataques por países.

df.Country.value_counts()
Países con mayor número de ataques

Y tras comprobar que USA es el país con mayor número de ataques, hice dos filtros: costa oeste y costa este para hacer después una comparativa entre ambos.

Creé una nueva columna para almacenar si pertenece a la costa oeste o no, donde indico si el área pertenece a la costa oeste, que la clasifique como “West” y si no es así, que la clasifique como “No west”

df['Coast']= df['Coast'][df['Area'].isin(('Alaska', 'Hawai', 'California', 'Oregon', 'Washington'))] = 'West'df['Coast'][~df['Area'].isin(('Alaska', 'Hawai', 'California', 'Oregon', 'Washington'))] = 'No west'

Y finalmente, ploteo los resultados para ver una gráfica de la clasificación:

df.Coast.value_counts().plot.pie(explode=(0, 0.15), title ='Shark Attacks')
Gráfica de la comparativa de ataques en la costa oeste de USA vs. el resto del mundo

El gráfico representa bien que la proporción de ataques en la costa oeste de USA ha sido menor (10.3%), por lo que se rechaza la hipótesis de que el mayor número de ataques a surfistas se produjo en la costa oeste de Estados Unidos.

Conclusiones finales

La limpieza de un DataFrame es el proceso más delicado del análisis de datos, ya que fácilmente puede obviarse o eliminarse información útil para tomar decisiones. Aunque existen muchas más posibilidades para explorar datos, filtrar y analizar, estos métodos son muy útiles para tomar una perspectiva de la información que contiene el DataFrame. ¡Seguimos!

--

--

Patricia Carmona
Ironhack

Data Analyst. Improving the relation brands-users.