Análisis Exploratorio de datos (EDA) con Apache Spark

Javier Madriz - Sep 25 - - Dev Community

Que es un analisis exploratorio de datos y por que es importante?

El análisis exploratorio de datos (EDA) nos ayuda a entender la estructura de los datos, identificar anomalías y detectar posibles transformaciones necesarias para un procesamiento adecuado. Desde la perspectiva de un ingeniero de datos, el EDA es clave para planificar las correcciones y optimizaciones que se implementarán más adelante en un pipeline ETL.

En este post, nos enfocaremos en detectar anomalías en los datos, dejando el análisis estadístico y la búsqueda de correlaciones para los analistas. Identificaremos las correcciones necesarias y explicaremos su importancia, para luego implementarlas en un pipeline de datos con AWS Glue y Apache Spark en un post posterior. ¡Será una serie completa e interesante!

Conjunto de datos

El conjunto de datos que vamos a utilizar para este ejercicio contiene datos sobres las 100 corporaciones con una cultura apegada a la sostenibilidad y amigables con el medio ambiente, el cual lo pueden conseguir en Kaggle: Descarga aqui el conjunto de datos

El entorno para hacer la exploración de los datos puede ser cualquier de tu preferencia, yo lo hare en un notebook de Glue.

Lo principal es leer los datos, te mostrare como se leen desde glue, no te preocupes si no entiendes el código, posteriormente hare una serie de glue donde lo aprenderás a profundidad, ahora el interés esta puesto en como y porque explorar la data.

dyf = glueContext.create_dynamic_frame.from_catalog(
    database = "greencompany",
    table_name = "greencompanies",
    transformation_ctx = "greencompaniessource",
    format_options = {"withHeader": True}
)
Enter fullscreen mode Exit fullscreen mode
  1. Análisis del Esquema de los Datos: Para comprender mejor nuestro dataset, comenzamos por examinar su esquema. Esto nos permite identificar las columnas que lo componen y sus respectivos tipos de datos, lo que es crucial para garantizar la calidad de los datos y la precisión en los análisis posteriores.

Como se hace esto en spark?

dyf.printSchema()

Image description

Que podemos observar?

Columna Previous Rank: Actualmente, esta columna tiene un tipo de dato String, es recomendable cambiar al tipo de dato Integer. Esta conversión permitirá realizar comparaciones y cálculos de manera más eficiente, mejorando la calidad de los análisis posteriores.

Columnas que en sus nombres contienen (%): El uso del símbolo de porcentaje en los nombres de las columnas puede dificultar el análisis y el filtrado de datos. Es recomendable evitar este tipo de símbolos en los nombres, ya que existen otras formas de indicar la referencia de cada columna sin complicar su uso. Optar por nombres más descriptivos y sin caracteres especiales facilitará el análisis de datos y mejorará la claridad en la interpretación de los resultados.

Columnas que almacenan datos numéricos: Las columnas que almacenan datos numéricos (Revenue, Profit, CEO Pay Ratio, Women on Board, Women in Leadership y Women in Workforce) deben tener su tipo de datos cambiado a integer o float, según corresponda. Esto permitirá aprovechar al máximo su uso en análisis y cálculos.

Una simple inspección al esquema nos dejo ver múltiples transformaciones necesarias, sigamos explorando.

Ahora miremos algunas registros de nuestros datos para a ver que mas conseguimos:

Convertimos nuestro dynamic frame que es lo que usa glue a un dataframe de pyspark para usar una sintaxis con la que estamos mas relacionados.

df = dyf.toDF()
df.show(3)
Enter fullscreen mode Exit fullscreen mode

Podremos observar todas las columnas y solo 3 registros, me centrare en la columna "Location"

Image description

Columna Location: Contiene tanto la ciudad como el país. Sería útil crear columnas separadas para ciudad y país, lo que proporcionaría información más granular para los analistas.

Tamaño de nuestros datos: Es fundamental conocer el tamaño de nuestros datos para implementar buenas prácticas de rendimiento, como ajustar el número de workers, particiones o definir la persistencia de los datos. A diferencia de Pandas, donde usamos df.shape, en Spark no hay una función nativa para esto, pero podemos obtener la cantidad de filas usando df.count() y el número de columnas con len(df.columns). Esto nos permitirá conocer el tamaño de nuestros datos para planificar mejor la ejecución y optimización de los trabajos.

row = df.count()
columnas = len(df.columns)
print((row, columnas))
Enter fullscreen mode Exit fullscreen mode

Columnas categóricas: Al trabajar con columnas categóricas como "Climate Grade", es esencial verificar la consistencia de los valores. Usar distinct() ayuda a identificar las categorías únicas y detectar posibles duplicados que podrían no ser evidentes, como diferencias causadas por espacios, símbolos o variaciones en la escritura. Esto asegura la calidad de los datos, evitando problemas en el análisis o modelado. Un ejemplo común es una columna de género que puede contener registros como "F", "M" y "Female", donde "F" y "Female" deberían ser tratados como la misma categoría.

df.select('Climate Grade').distinct().show()
Enter fullscreen mode Exit fullscreen mode

Image description

Conteo de nulos por columna: Identificar valores nulos es crucial para asegurar la calidad del análisis de datos. Tener un claro entendimiento de en qué columnas se encuentran y en qué cantidad permite tomar decisiones informadas sobre cómo tratarlos. En Pandas, esto se logra fácilmente con df.isnull().sum(), pero en Spark, el proceso es un poco más complejo debido a la naturaleza distribuida de los datos, como siempre hay muchas formas de hacer las cosas yo suelo hacerlo de la siguiente manera:

null_per_columns = df.select([sum(col(c).isNull().cast('int')).alias(c) for c in df.columns])
null_per_columns.show()
Enter fullscreen mode Exit fullscreen mode

Image description

Consistencia de datos: Al analizar las variables categóricas, verificamos si hay repeticiones inesperadas. Sin embargo, no siempre la solución es tan directa, y en ocasiones debemos considerar la consistencia de los datos. Por ejemplo, en nuestro dataset, la columna "Company" podría sugerir que ninguna compañía debería repetirse, ya que estamos trabajando con datos sobre empresas eco-friendly organizadas en una especie de ranking. Sin embargo, la columna "Industry" introduce una excepción importante: ¿qué pasa si una misma compañía opera en varias industrias? En ese caso, sería válido que una compañía aparezca varias veces en el dataset, pero diferenciada por la industria en la que opera, como suele suceder con las filiales de grandes empresas. Para verificar esto, podemos agrupar por Company y contar cuántas industrias únicas tiene cada una.

El siguiente código agrupa las compañías y calcula cuántas industrias distintas están asociadas a cada una:

inconsistencia = df.groupBy('Company').agg(countDistinct('Industry').alias('industrias_unicas'))
inconsistencia.show(10)
Enter fullscreen mode Exit fullscreen mode

Image description

Hasta ahora, hemos conocido varios aspectos clave del análisis exploratorio de datos y el propósito que buscamos con esta práctica. Resumiendo las transformaciones necesarias para nuestros datos, encontramos los siguientes puntos:

  • Convertir la columna "Previous Rank" de string a integer.

  • Corregir los nombres de columnas que necesitan incluir el símbolo (%).

  • Columnas que almacenan datos de capital, ganancias, proporciones etc, corregir cambiando el tipo de datos de string a float o integer.

  • La columna "Location" contiene la ciudad y país, se debe separar la columna "Location" en dos columnas independientes: una para ciudad y otra para país.

  • Manejo de nulos, bien sea reemplazándolos por un valor estadístico o simplemente eliminándolos si no generan ningún impacto significativo.

Estas transformaciones las implementaremos en un pipeline de datos en AWS, utilizando Glue, Crawlers, el Catálogo de Datos, S3, y Athena para realizar consultas y asegurarnos de que nuestros datos estén limpios. Esta será la primera entrega de una serie de tutoriales sobre AWS Glue, donde explicaremos cada uno de los componentes, cual es su proposito, como debemos integrarlos en nuestro pipeline y en que escenarios se debe usar unos u otros.

Como siempre les digo, si tienen alguna opinión, duda no dejen de interactuar con el contenido.

Hasta la proxima.

. . . . . . . . . . . .