Parquet: un formato de datos optimizado para rendimiento y eficiencia

_Benchmarks_ comparativos de velocidad de escritura, lectura y peso entre Parquet, Excel y CSV

4/9/2026

datos optimización

Entre todos los formatos para almacenar datos que existen (Excel, CSV, etc.), recientemente hay uno que destaca. El formato Parquet, del proyecto Apache Arrow, implementado en R mediante el paquete {arrow}, es un formato moderno diseñado para eficiencia y velocidad.

A diferencia de otros formatos de datos diseñados para ser editables y visuales, como Excel, o diseñados para simplicidad y estandarización, como CSV y otros basados en texto, Parquet es un formato que usa tecnologías modernas para ser más rápido de leer, más liviano, soportar grandes volúmenes de datos, y permitir operaciones eficientes sobre la información.

Además, es un formato de datos estándar, en el sentido de que es posible de cargar desde casi cualquier software: C, Java, R, Python, Rust, Go, Swift y más.

Instala el paquete {arrow}:

install.packages("arrow")

Usarlo es muy simple: read_parquet() para leer datos formato Parquet, y write_parquet() para guardar tus datos en este formato.

Comparación de velocidad

Para destacar las cualidades de Parquet, haremos una comparación con datos ficticios entre Excel, CSV y Parquet.

Con este código crearemos una tabla de 1 millón de filas (que no es mucho, pero lamentablemente se acerca al máximo de Excel), con 10 columnas con datos al azar.

library(arrow)
library(dplyr)

n <- 1000000 # 1 millón de filas

tabla <- tibble(
  id = 1:n,
  a = rnorm(n),
  b = rnorm(n),
  c = rnorm(n),
  d = rnorm(n),
  e = rnorm(n, mean = 100),
  f = rnorm(n, mean = 10, sd = 5),
  letras = sample(letters, size = n, replace = TRUE),
  animal = sample(c("gato", "rata", "pato"), size = n, replace = TRUE),
  fechas = sample(1980:2026, size = n, replace = TRUE)
)

Prueba 1: escribir datos

La primera prueba será la velocidad para guardar datos en los tres formatos. Crearemos rutas a archivos temporales para no tener que definir rutas manuales. Los archivos temporales se guardan en un lugar invisible y se eliminan solitos después de terminar la sesión.

archivo_parquet <- tempfile(fileext = ".parquet")
archivo_csv <- tempfile(fileext = ".csv")
archivo_xlsx <- tempfile(fileext = ".xlsx")

Ahora ejecutaremos un benchmark con el paquete {bench} para comparar la velocidad de escritura de la tabla de 1 millón de filas:

bench::mark(
  "excel" = openxlsx2::write_xlsx(tabla, archivo_xlsx),
  "csv" = readr::write_csv(tabla, archivo_csv),
  "parquet" = arrow::write_parquet(tabla, archivo_parquet),
  check = FALSE,
  iterations = 10,
)
expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
<bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 excel         32.3s    35.9s    0.0282    1.81GB   0.0734    10    26      5.91m
2 csv         279.2ms  312.2ms    0.748     8.81MB   0         10     0     13.37s
3 parquet     297.7ms  314.4ms    1.56      5.51MB   0         10     0      6.41s

Recibimos los resultados de la comparación de desempeño. Escribir un Excel de 1 millón de filas demoró 32 segundos! Mientras que el CSV y el Parquet tardaron 0.31 segundos ambos, aunque el Parquet usó menos menos memoria y tardó la mitad del tiempo total (6 segundos versus 13 segundos).

🥇 Ganador en velocidad de escritura: empate entre CSV y Parquet!

Prueba 2: peso de los archivos

Otro factor importante al trabajar datos es el almacenamiento que utilizan. Distintos formatos usan distintas aproximaciones de compresión, lo que resulta en distintos pesos.

Comparemos el peso de los archivos creados en la prueba anterior:

library(cli)

peso_xlsx <- file.size(archivo_xlsx)/1024^2
peso_csv <- file.size(archivo_csv)/1024^2
peso_parquet <- file.size(archivo_parquet)/1024^2

cli_inform("Peso de archivo Excel: {round(peso_xlsx, 1)} Mb")
cli_inform("Peso de archivo CSV: {round(peso_csv, 1)} Mb")
cli_inform("Peso de archivo Parquet: {round(peso_parquet, 1)} Mb")
Peso de archivo Excel: 97.4 Mb
Peso de archivo CSV: 128.5 Mb
Peso de archivo Parquet: 53.3 Mb

Nuevamente, Parquet produce mejores resultados, ya que usa tecnologías modernas de compresión centradas en datos columnares, y además produce archivos binarios, que si bien no son legibles por humanos (como sí lo es CSV, ya que es puro texto), tiene otros beneficios; en este caso, peso y velocidad.

diferencia <- file.size(archivo_parquet)/file.size(archivo_csv)
cli_alert_success("El archivo Parquet es un {round(diferencia*100, 1)}% más liviano que el CSV")
✔ El archivo Parquet es un 41.5% más liviano que el CSV

🥇 Ganador en peso de archivos: Parquet!

Prueba 3: lectura de datos

Ahora viene la prueba definitiva: la carga de datos! Incluiremos otro contrincante más: la lectura de CSVs con Arrow, que teóricamente es más rápida que otras implementaciones.

Realizamos el benchmark de lectura de datos:

bench::mark(
  "excel" = openxlsx2::read_xlsx(archivo_xlsx),
  "csv" = readr::read_csv(archivo_csv),
  "arrow_csv" = arrow::read_csv_arrow(archivo_csv),
  "arrow_parquet" = arrow::read_parquet(archivo_parquet),
  check = FALSE,
  iterations = 10,
)
expression         min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
<bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 excel            19.2s    23.5s    0.0446    3.92GB    0.165    10    37      3.74m
2 csv            467.2ms  500.5ms    1.76     77.99MB    0.176    10     1      5.67s
3 arrow_csv      103.8ms    111ms    8.87     11.97MB    0        10     0      1.13s
4 arrow_parquet   38.3ms   40.3ms   24.4        1.6MB    0        10     0   409.94ms

Aquí vemos diferencias gigantes! Cargar una tabla Excel de 1 millón de filas demoró en promedio 23 segundos, mientras que leer los mismos datos en Parquet demoró 40.3 milisegundos!

Esto significa que Parquet es 583.1 veces más rápido que Excel y 12.4 veces más rápido que CSV. Por otro lado, leer un CSV usando Arrow es 4.5 veces más rápido que con {readr}, aunque sigue siendo 2.7 veces más lento que usar Parquet.

🥇 Ganador en lectura de datos: Parquet!

La velocidad de carga de datos tiene implicancias gigantes en el desempeño de tus análisis de datos diarios, pero también cuando te enfrentes a grandes volúmenes de datos.

Prueba 4: lectura de grandes volúmenes de datos

Repitamos el ejercicio con un dataframe de 30 millones de filas y 10 columnas, lo que descalifica de inmediato a Excel. Así nos pondremos en casos de conjuntos de datos más difíciles de manejar.

Creamos los datos de prueba y los guardamos:

n <- 30000000 # 30 millones de filas

tabla2 <- tibble(
  id = 1:n,
  a = rnorm(n),
  b = rnorm(n),
  c = rnorm(n),
  d = rnorm(n),
  e = rnorm(n),
  f = rnorm(n),
  g = rnorm(n),
  h = rnorm(n),
  i = rnorm(n, mean = 100),
  j = rnorm(n, mean = 10)
)

# rutas
archivo_csv2 <- tempfile(fileext = ".csv")
archivo_parquet2 <- tempfile(fileext = ".parquet")

# escribir
readr::write_csv(tabla2, archivo_csv2)
arrow::write_parquet(tabla2, archivo_parquet2)

Revisemos el peso de los archivos resultantes:

library(cli)

peso_csv2 <- file.size(archivo_csv2)/1024^2
peso_parquet2 <- file.size(archivo_parquet2)/1024^2

cli_inform("Peso de archivo CSV: {round(peso_csv2, 1)} Mb")
cli_inform("Peso de archivo Parquet: {round(peso_parquet2, 1)} Mb")
Peso de archivo CSV: 5789 Mb
Peso de archivo Parquet: 2495.2 Mb

Nuevamente vemos que Parquet genera archivos más livianos. Ahora procedemos a hacer la prueba de lectura de estos archivos de 30 millones de filas:

bench::mark(
  "csv" = readr::read_csv(archivo_csv2),
  "arrow_csv" = arrow::read_csv_arrow(archivo_csv2),
  "arrow_parquet" = arrow::read_parquet(archivo_parquet2),
  check = FALSE,
  iterations = 4,
)
expression         min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
<bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 csv             10.98s   11.59s    0.0861    2.46GB   0.0861     4     4      46.5s
2 arrow_csv        4.55s    4.62s    0.207   118.82MB   0          4     0      19.3s
3 arrow_parquet 787.16ms    1.55s    0.367      1.6MB   0          4     0      10.9s

Confirmamos que, incluso cargando una tabla de datos grande, leer un Parquet es 10 veces más rápido que CSV, utilizando una fracción minúscula de la memoria necesaria. Un detalle es que Arrow usa todos los procesadores disponibles para cargar los datos:

Funcionalidades de Arrow/Parquet

Pero además de ser veloz, usar Parquet trae otros beneficios!

Carga parcial de columnas

Una característica útil es poder cargar datos seleccionando las columnas, dado que Parqeut almacena los datos por columna.

Para probarlo, carguemos el archivo de 30 millones de filas, primero completo y después solamente obteniendo las columnas id y a:

bench::mark(
  "completo" = arrow::read_parquet(archivo_parquet2),
  "columnas" = arrow::read_parquet(archivo_parquet2, col_select = c("id", "a")),
  check = FALSE
)
  expression      min median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
  <bch:expr> <bch:tm> <bch:>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 completo      974ms  974ms      1.03    7.96KB        0     1     0      974ms
2 columnas      287ms  300ms      3.33   14.44KB        0     2     0      600ms

Al seleccionar solamente lo necesario, el tiempo de carga se reduce a un tercio!

Cargar datos como dataset

Otra ventaja de usar datos Arrow es la función open_dataset(). Esta función permite cargar los datos como si fueran una base de datos. Esto significa que R no carga los datos en la memoria, sino que devuelve un esquema de los datos, sobre el cual usamor la sintaxis de {dplyr} para hacer consultas (querys) a los datos. Estas querys se procesan internamente por Arrow, directamente desde el disco duro.

Gracias a esta funcionalidad, el motor de base de datos de Arrow realiza el trabajo de obtención y procesamiento de los datos de manera más eficiente. El trabajo sólo se ejecuta cuando hacemos collect(), entregándonos solamente el resultado final, ahora sí como dataframe. Esto evita que conjuntos de datos grandes saturen la memoria de nuestro computador, posibilitando incluso cargar archivos más grandes que la memoria RAM.

bench::mark(
  "parquet" = arrow::read_parquet(archivo_parquet2) |> 
    summarize(
      across(
        everything(),
        mean)
    ),
  "dataset" = arrow::open_dataset(archivo_parquet2) |> 
    summarize(
      across(
        everything(),
        mean)
    ) |> 
    collect(),
  iterations = 10
)
expression      min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
<bch:expr> <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 parquet       1.58s    2.23s     0.425    14.5KB    0        10     0     23.52s
2 dataset    903.74ms    1.03s     0.921   488.4KB    0.230     8     2      8.68s

En la comparación, vemos que consultar y procesar los datos de 30 millones de filas como dataset es el doble de rápido que cargarlos directamente. Para más información, consulta la documentación oficial.

Cargar archivos CSV con Arrow

Como vimos más arriba, Arrow también incluye una función de lectura más rápida de archivos CSV.

bench::mark(
  "csv" = readr::read_csv(archivo_csv),
  "arrow_csv" = arrow::read_csv_arrow(archivo_csv),
  check = FALSE,
  iterations = 20,
)
expression         min   median `itr/sec` mem_alloc `gc/sec` n_itr  n_gc total_time
<bch:expr>    <bch:tm> <bch:tm>     <dbl> <bch:byt>    <dbl> <int> <dbl>   <bch:tm>
1 csv            467.2ms  500.5ms    1.76     77.99MB    0.176    10     1      5.67s
2 arrow_csv      103.8ms    111ms    8.87     11.97MB    0        10     0      1.13s

En resumidas cuentas, recomiendo empezar a usar el formato Parquet para almacenar datos! Hará tu trabajo más eficiente

Referencias

Fecha de publicación:
4/9/2026
Extensión:
9 minute read, 1713 words
Tags:
datos optimización
Ver también:
Creando una función para consultar datos en R
Potencia las capacidades de la IA entregándole herramientas (_tool calling_) basadas en R
Explorar datos del Censo de Población y Vivienda 2024 con R