A la hora de analizar un conjunto de datos es muy importante el paso previo, el de la limpieza. Y es que es tan importante que, según un estudio, los analistas de datos invierten el 80% de su tiempo en el preparado de los datos antes de examinarlos.
Así que si lo que quieres es sacar unas estadísticas y conclusiones representativas a partir de un conjunto de datos, deberás prestar mucha atención a esta parte.
Vamos a ver cómo podemos hacerlo utilizando el lenguaje de programación Python y ayudándonos con una de sus librerías más importantes, Pandas. Pero antes de nada, si estás empezando con esto, puede que te interese leer el siguiente artículo primero:
En este artículo hablaremos de:
Quitar duplicados y filas vacías.
Eliminar columnas poco relevantes.
Buscar y quitar outliers.
Mejorar los datos.
Para poner en práctica esta técnica de limpieza de datos, vamos a utilizar la encuesta realizada a programadores por Stack Overflow este último año. Puedes descargarte el archivo csv desde aquí. Y si quieres ver el código utilizado para limpiar los datos, lo tienes en mi cuenta de Github.
Cargar csv y familiarizarse con los datos
Una de las ventajas de Python, además de su sencillez, es la facilidad con la que podemos cargar archivos y trabajar sobre ellos. Y cuando se trata de análisis de datos, el tipo de archivo utilizado por excelencia es el csv.
El primer paso será importar las librerías que vamos a utilizar y cargar el archivo sobre el que vamos a trabajar. En este caso el archivo ya tiene un índice propio, representado por el ID de cada respuesta. Así que es importante decirle que tome esa columna como índice, de lo contrario nos creará otro índice a mayores. Para ello utilizamos “index_col=0“.
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
# Load the csv file:
df = pd.read_csv('/survey_results_public.csv', index_col=0, thousands='.')
Una vez cargados los datos, es importante familiarizarse con la tabla y ver cómo está organizada. Para esto tenemos diferentes recursos, como por ejemplo:
print(df.loc[2])
print(df.info())
print(df.shape)
print(df.columns)
print(df.head())
print(df.tail())
Quitar duplicados y filas vacías
Este paso es muy sencillo, pero en el caso de tener una tabla muy pesada nos va a ser muy útil para empezar a aligerarla. Simplemente, con dos líneas de código le vamos a decir que elimine las filas con valores duplicados y aquellas que estén completamente vacías.
En el caso de tener mucha información y querer hacer un estudio más preciso, también podríamos eliminar aquellas filas en las que les falte un solo dato, en vez de las que están completamente vacías. Si le quitamos el “how=all“, borrará las filas a las que le falta algún dato.
# Clean all duplicates
df = df.drop_duplicates(inplace=True)
# Drop rows that are completely empty
df = df.dropna(how='all')
Eliminar columnas poco relevantes
A menudo nos encontraremos con demasiada información en la tabla y muchas columnas no serán relevantes para los análisis que queremos realizar. Para quitar columnas podemos crear una lista con sus nombres y luego utilizar la función “.drop()“ para eliminarlas de la tabla.
También podremos eliminar columnas en función del porcentaje de datos nulos que tenga. En este ejemplo borramos las columnas que tienen más de un 55% de datos nulos.
La gestión de los valores nulos es muy importante. Con la ayuda de la librería seaborn se puede ver gráficamente la cantidad de datos nulos que tenemos, y será de gran utilidad para ver el antes y el después de nuestra limpieza.
# How many null values do we have in each column?print(df.isnull().any())
# Percentage of null values in each column
print(df.isnull().sum()/df.shape[0])
# Another way to see null values
print(sns.heatmap(df.isnull(), yticklabels=False))
# Clear all columns that have more than a specific percentage of null values
limit = len(df)*0.55
df = df.dropna(thresh=limit, axis=1, inplace=True)
# Clear unuseful columns for the queries we are looking for
to_drop = ['Age1stCode', 'OrgSize', 'MiscTechHaveWorkedWith', 'WebframeHaveWorkedWith', 'WebframeWantToWorkWith', 'NEWCollabToolsWantToWorkWith', 'NEWOtherComms', 'Trans', 'Sexuality', 'Ethnicity', 'Accessibility', 'MentalHealth', 'SurveyLength', 'SurveyEase']
df = df.drop(to_drop, inplace=True, axis=1)
Buscar y quitar outliers
Los outliers son datos que corrompen la muestra porque está muy alejados de la media. Esto puede deberse a errores a la hora de introducirlos, por eso es importante localizarlos y quitarlos de nuestra tabla.
Hay diferentes técnicas para realizar la limpieza de outliers, y una de las más utilizadas es la regla del IQR (Inter-Quartile-Range), que es la que aplicamos en este ejemplo. Utilizando como referencia el percentil 25% y 75%, se puede aplicar una fórmula y localizar los datos no representativos.
# See the outliers
plt.boxplot(df['CompTotal'], vert=False)print(plt.show())
# Drop the outliers
Q1 = df['CompTotal'].quantile(0.25)
Q3 = df['CompTotal'].quantile(0.75)
IQR = Q3 - Q1
lower_limit = (Q1 - 1.5 * IQR)
upper_limit = (Q3 + 1.5 * IQR)
df = df[(df['CompTotal'] >= lower_limit) & (df['CompTotal'] <= upper_limit)]
Mejorar los datos
Una vez eliminados los datos erróneos o que no nos hacen falta, el último paso será mejorar los datos en la manera que mejor nos convenga para su posterior análisis.
Por ejemplo, ver aquellas columnas que tienen información numérica pero están almacenados como string, es decir, como si fueran palabras. Debemos modificar el tipo de dato que son para poder usarlo en las fórmulas.
Rellenar los huecos vacíos de las columnas que contienen información numérica. De esta manera podremos hacer cálculos con una muestra más fiable. La técnica de rellenado se puede hacer de muchas maneras, en este caso se rellenaron con la mediana.
También podemos ir investigando los datos de cada columna y ver que nos choca. Por ejemplo, en la columna de los países, Reino Unido se almacenó como “United Kingdom of Great Britain and Northern Ireland“. Esto nos va a perjudicar a la hora de hacer gráficos, así que lo mejor es reemplazarlo por nombres más cortos, en este caso “UK”.
# Improve data types. There are columns with numbers as an object so we change it to float
print(df.dtypes)
df['YearsCode'] = df['YearsCode'].apply(pd.to_numeric, errors='coerce')
df['YearsCodePro'] = df['YearsCodePro'].apply(pd.to_numeric, errors='coerce')
# Fill the null values for each column with its mean
df.YearsCode.fillna(df.YearsCode.median(), inplace=True)
df.YearsCodePro.fillna(df.YearsCodePro.median(), inplace=True)
df.CompTotal.fillna(df.CompTotal.median(), inplace=True)
df.ConvertedCompYearly.fillna(df.ConvertedCompYearly.median(), inplace=True)
# See everything works
print(df.isnull().sum()/df.shape[0])
# See how many answers are for each column and improve some
print(df.nunique())
# Improve Country column
print(df.Country.unique())
df = df['Country'].replace(['United Kingdom of Great Britain and Northern Ireland', 'Russian Federation', 'Hong Kong (S.A.R.)',
'Venezuela, Bolivarian Republic of...', 'Congo, Republic of the...', 'United States of America'],
['UK', 'Russia', 'Hong Kong', 'Venezuela', 'Congo', 'USA'], inplace=True)
# Make sure
print(df.groupby('Country').size()[0:50])
# Improve EdLevel column
print(df.groupby('EdLevel').size())
df = df['EdLevel'].replace(['Associate degree (A.A., A.S., etc.)', 'Bachelor’s degree (B.A., B.S., B.Eng., etc.)',
'Master’s degree (M.A., M.S., M.Eng., MBA, etc.)', 'Other doctoral degree (Ph.D., Ed.D., etc.)',
'Professional degree (JD, MD, etc.)', 'Secondary school (e.g. American high school, German Realschule or Gymnasium, etc.)'],
['Associate degree', 'Bachelor’s degree', 'Master’s degree','Other doctoral degree', 'Professional degree', 'Secondary school'], inplace=True)