Tidyverse en R: dplyr para manipular datos y ggplot2 para visualizarlos

El tidyverse no es un paquete sino una colección de paquetes que comparten filosofía, convenciones de nombres y una forma de encadenar operaciones que resulta muy legible. Lo creó Hadley Wickham mientras trabajaba en RStudio (hoy Posit) y desde entonces se ha convertido en el enfoque dominante para análisis de datos en R. Si abres cualquier análisis moderno en R es casi seguro que verás library(tidyverse) en las primeras líneas.

Los paquetes principales son: dplyr para manipular datos, ggplot2 para visualizarlos, tidyr para reorganizar la estructura de las tablas, readr para leer archivos planos, purrr para programación funcional, tibble como alternativa moderna al data frame, stringr para trabajar con texto y forcats para factores. Todos se cargan de golpe con library(tidyverse), aunque también puedes cargar solo el que necesitas.

dplyr: manipulación de datos con verbos

La idea central de dplyr es que las operaciones sobre datos se expresan con verbos que describen lo que haces: filtrar, seleccionar, mutar, ordenar, resumir, agrupar. Cada verbo es una función, y las funciones se encadenan con el pipe |>:

library(dplyr)

# Dataset de ejemplo
ventas <- data.frame(
  producto  = c("A", "B", "A", "C", "B", "A"),
  region    = c("Norte", "Sur", "Norte", "Sur", "Norte", "Sur"),
  importe   = c(1200, 800, 950, 1100, 700, 1350),
  trimestre = c(1, 1, 2, 2, 3, 3)
)

# Pipeline típico de análisis
resultado <- ventas |>
  filter(importe > 800) |>
  mutate(iva = importe * 0.21,
         total = importe + iva) |>
  group_by(producto, region) |>
  summarise(
    ventas_media  = mean(total),
    ventas_total  = sum(total),
    n_operaciones = n(),
    .groups = "drop"
  ) |>
  arrange(desc(ventas_total))

print(resultado)

Esto que ves arriba es un análisis completo: filtra filas, añade columnas calculadas, agrupa por dos variables y calcula estadísticas por grupo. La versión equivalente en base R sin dplyr funcionaría igual, pero sería bastante más difícil de leer a primera vista.

Las funciones más usadas de dplyr

  • filter(): filtra filas según condiciones lógicas.
  • select(): selecciona o elimina columnas.
  • mutate(): crea o modifica columnas.
  • arrange(): ordena filas, desc() para descendente.
  • summarise() / summarize(): calcula estadísticas de resumen.
  • group_by(): agrupa para que las operaciones siguientes sean por grupo.
  • join(): left_join(), inner_join(), full_join() para cruzar tablas.
  • across(): aplica la misma función a varias columnas a la vez.
# across() para aplicar funciones a varias columnas
iris |>
  group_by(Species) |>
  summarise(across(where(is.numeric), mean, .names = "media_{.col}"))

ggplot2: la gramática de los gráficos

ggplot2 está basado en el concepto de «gramática de gráficos» de Leland Wilkinson: un gráfico se construye sumando capas, donde cada capa añade algo visual (puntos, líneas, barras, áreas) sobre los datos. La función ggplot() define los datos y la correspondencia entre variables y atributos visuales (aes()); después se suman los geoms que se quieren mostrar:

library(ggplot2)

# Gráfico de dispersión básico
ggplot(mtcars, aes(x = wt, y = mpg, color = factor(cyl))) +
  geom_point(size = 3, alpha = 0.8) +
  geom_smooth(method = "lm", se = FALSE) +
  labs(
    title  = "Peso vs consumo de combustible",
    x      = "Peso (miles de libras)",
    y      = "Millas por galón",
    color  = "Cilindros"
  ) +
  theme_minimal() +
  theme(legend.position = "top")

Lo que hace potente a ggplot2 no es el gráfico básico, que en otros lenguajes también se puede hacer. Lo potente es que añadir facetas, cambiar el tema visual, ajustar escalas o agregar anotaciones son operaciones aditivas que no cambian la estructura del código:

# Añadir facetas por cilindros
ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point() +
  facet_wrap(~cyl, labeller = label_both) +
  theme_minimal()

# Gráfico de barras con errores
iris |>
  group_by(Species) |>
  summarise(
    media = mean(Sepal.Length),
    se    = sd(Sepal.Length) / sqrt(n())
  ) |>
  ggplot(aes(x = Species, y = media, fill = Species)) +
    geom_col(show.legend = FALSE) +
    geom_errorbar(aes(ymin = media - se, ymax = media + se), width = 0.2) +
    theme_classic()

tidyr: reorganizar la estructura de los datos

Muchos análisis fallan antes de empezar porque los datos no están en el formato que las funciones esperan. tidyr resuelve esto con pivot_longer() y pivot_wider():

library(tidyr)

# Datos en formato ancho
datos_ancho <- data.frame(
  persona = c("Ana", "Luis"),
  enero   = c(100, 150),
  febrero = c(120, 130),
  marzo   = c(90, 160)
)

# Convertir a formato largo (útil para ggplot2)
datos_largo <- datos_ancho |>
  pivot_longer(cols = -persona,
               names_to  = "mes",
               values_to = "ventas")

print(datos_largo)

El tidyverse y los datos reales

Una virtud del tidyverse es que funciona bien con datos sucios. readr lee CSVs con tipos automáticos y mensajes de error claros. stringr tiene funciones consistentes para manipular texto (todas empiezan por str_). forcats gestiona factores con funciones igualmente coherentes (todas empiezan por fct_).

El tidyverse tiene alguna penalización de rendimiento frente a base R o data.table cuando los datos son muy grandes, más de un millón de filas. Para esos casos, data.table es una alternativa mucho más rápida que también se puede combinar con tidyverse cuando hace falta. Para una visión más amplia del lenguaje puedes ver la introducción a R 4.5 y compararlo con Julia para ciencia de datos.

Imagen: Pexels / Pavel Danilyuk

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP