Uncategorized28 de enero de 2025
PANDAS VS POLARS: SENCILLEZ VS EFICIENCIA
PANDAS VS POLARS: SENCILLEZ VS EFICIENCIA
Pandas ha sido la herramienta principal para la transformación y análisis de datos durante años. Sin embargo, en los ultimos años, han aparecido nuevas herramientas que permiten realizar estas mismas tareas igualmente. Una de estas nuevas opciones es Polars.
Pandas ha sido la herramienta principal para la transformación y análisis de datos durante años, y la preferida por los científicos de datos con diferencia. Es fácil, de usar, con funciones sencillas e intuitivas, y permite a aquellos que se están iniciando en el mundo de los datos aprender las nociones básicas del ETL. Esto ha permitido que los usuarios creen una gran cantidad de tutoriales y documentación, haciendo más accesible a los nuevos usuarios el inicio.
Sin embargo, en los ultimos años, han aparecido nuevas herramientas que permiten realizar estas mismas tareas igualmente. Una de estas nuevas opciones es Polars, lanzado en junio de 2024. Entre las mejoras que incorpora Polars respecto a Pandas están:
- Evaluación diferida
- API más clara y funcional
- Procesamiento en paralelo
- Optimización de la memoria
En este blog vamos a analizar tiempos de ejecución de estas dos librerías tanto para procesos sencillos como para procesos de tratamiento de datos más complejos. Además se calcularán los tiempos usados en cada tipo de operación y en total, a lo largo de 10 iteraciones. Los procesos a ejecutar son:
- Carga de datasets desde .csv
- Concatenación de dataframes
- Reordenación de entradas
- Filtrado de entradas respecto a un valor
- Transformación de una columna
# PRUEBAS
# PANDAS #
#### Ordenación
```python
pd_df.sort_values(by="deaths", ascending=False)
```
El tiempo medio de ejecución de esta consulta en un notebook es 1.00104 ms, llegando a un tiempo máximo de 2.00277 ms.
#### Filtrado
```python
pd_df_filtered = pd_df[(pd_df["deaths"] > 1000) & (pd_df["region"] == "Turkey")]
```
El tiempo medio de ejecución es de 0.29994 ms con un tiempo máximo de 1.00185 ms.
#### Transformación
```python
pd_df["month"].apply(convert_month)
```
El tiempo medio de ejecución es de 0.20017 ms con un tiempo máximo de 1.00183 ms.
#### Proceso completo
```python
pd_df_1 = pd.read_csv("data/earthquakes.csv")
pd_df_2 = pd.read_csv("data/earthquakes_2.csv")
pd_df = pd.concat([pd_df_1, pd_df_2], axis=0, ignore_index=True)
pd_df.sort_values(by="deaths", ascending=False)
pd_df_filtered = pd_df[(pd_df["deaths"] > 1000) & (pd_df["region"] == "Turkey")]
pd_df_filtered["month"].apply(convert_month)
pd_df_filtered.to_csv("data/earthquakes_combined_pd.csv", index=False)
```
En esta parte se mide el tiempo total de estos procesos hasta llegar a guardar los nuevos datos en un archivo cvs. En total, de media, este proceso usando **Pandas** tardó 9.352 ms.
# POLARS #
#### Ordenación
```python
pl_df.sort(by="deaths", descending=True)
```
El tiempo medio de ejecución de este código en un jupyter notebook es de 0.59876 ms con un tiempo máximo de 2.00128 ms.
#### Filtrado
```python
pl_df_filtered = pl_df.filter((pl.col("deaths") > 1000) & (pl.col("region") == "Turkey"))
```
El tiempo medio de ejecución es de 0.96478 ms con un tiempo máximo de 4.54258 ms.
#### Transformación
```python
pl_df.with_columns(pl.col("month").replace_strict(month_map))
```
El tiempo medio de ejecución es de 2.20010 ms y el tiempo máximo es de 1.700019 ms.
#### Proceso completo
```python
pl_df_1 = pl.read_csv("data/earthquakes.csv", null_values="NA")
pl_df_2 = pl.read_csv("data/earthquakes_2.csv", null_values="NA")
pl_df = pl.concat([pl_df_1, pl_df_2])
pd_df.sort_values(by="deaths", ascending=False)
pl_df_filtered = pl_df.filter((pl.col("deaths") > 1000) & (pl.col("region") == "Turkey"))
pl_df_filtered.with_columns(pl.col("month").replace_strict(month_map))
pl_df_filtered.write_csv("data/earthquakes_combined_pl.csv")
```
El tiempo medio de ejecución de todo el proceso completo usando **Polars** es de 5.051 ms.
# CREAMOS UN SET DE PRUEBAS A MAYORES, PARA VERIFICAR RESULTADOS #
Para finalizar también se ejecutó un proceso más complejo, con operaciones encadenadas y cálculos más costosos con ambas librerías.
#### Pandas
```python
pd_df = pd.read_csv("data/earthquakes.csv")
pd_df["month"] = pd_df["month"].apply(convert_month)
avg_death_by_month = pd_df.groupby("month")["deaths"].mean()
```
#### Polars
```python
pl_df = pl.read_csv("data/earthquakes.csv", null_values="NA")
pl_df = pl_df.with_columns(pl.col("month").replace_strict(month_map))
avg_death_by_month = pl_df.group_by("month").agg(pl.col("deaths").mean())
```
El timepo medio de esta ejecución con **Pandas** fue de 4.453 ms mientras que con **Polars** fue solo de 1.600 ms.
# RESULTADOS #
Se ha comprobado que en procesos separados, en los que se consultan datos de manera constante, la *ganadora* se puede considerar **Pandas**, ya que aunque en la ordenación obtuvo un tiempo mínimamente peor, sí que obtuvo mejores marcas en el resto de procesos.
Sin embargo, cuando las operaciones se concatenan sin la necesidad de consultar los datos, o se realizan operaciones más complejas con muchos datos, **Polars** es claramente superior, llegando incluso a ser 2.78 veces más rápido que **Pandas**.
# CONCLUSIONES #
Ambas librerías tienen sus beneficios en comparación con la otra. **Pandas** tiene una curva de aprendizaje rápida, que permite crear pequeños proyectos o funciones de manera rápida y sencilla. Es idóneo para aquellas personas que están empezando o tienen poca experiencia en el mundo de los datos. Como contraposición, si alguien ya tiene experiencia, conoce lenguajes como SQL, o tiene acceso a un cluster que permita la paralelización de procesamientos, debe elegir **Polars**. La documentación de esta última es bastante menor, y los ejemplos prácticos son más escasos, lo cual hace que la curva de aprendizaje sea más difícil, pero las capacidades son mucho mayores.