0Pricing
R Academy · Lección

Anidación y desanidación de data frames

Use nest() y unnest() para trabajar con list-columns en flujos de trabajo tidy.

Anidación y desanidación de data frames es una lección gratuita de R Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de R Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de R Academy incluye 4 lecciones en total.

Columnas de listas y datos anidados

Una columna de listas es una columna de un data frame en la que cada celda contiene un objeto de R (un vector, un data frame, un modelo o una lista). Esto permite almacenar subdatos estructurados junto a otras columnas y habilita flujos de trabajo potentes por grupos.

library(tidyr)
library(dplyr)

# A simple data frame with a list-column
df <- data.frame(
  group = c('A','B','C'),
  n = c(3, 2, 4)
)
df$values <- list(c(1,2,3), c(4,5), c(6,7,8,9))

print(df)
print(df$values[[1]])  # Access the first list element

nest() — Crear data frames anidados

nest(df, data = c(col1, col2)) agrupa las filas según las columnas no anidadas y agrupa las columnas especificadas en una columna de listas de data frames. Hay una fila por grupo, y cada una contiene un pequeño data frame.

library(tidyr)
library(dplyr)

df <- data.frame(
  region = c('East','East','East','West','West'),
  month = c(1,2,3,1,2),
  sales = c(100,120,110,200,190)
)

nested <- df %>%
  nest(data = c(month, sales))

print(nested)
print(nested$data[[1]])  # East region's data

nest() con group_by()

El patrón más habitual consiste en usar group_by() y después nest() para crear una fila por grupo, agrupando todas las columnas restantes en una columna de listas data. Es equivalente a nest(.by = group_col) en las versiones más recientes de tidyr.

library(tidyr)
library(dplyr)

df <- data.frame(
  category = c('A','A','A','B','B','C','C','C','C'),
  x = c(1,2,3,4,5,6,7,8,9),
  y = c(2,4,3,8,7,5,6,9,8)
)

nested <- df %>%
  group_by(category) %>%
  nest()

print(nested)
cat('Rows per category B:', nrow(nested$data[[2]]))

map() con data frames anidados

Una vez anidados los datos, use purrr::map() para aplicar una función a cada pequeño data frame. La función recibe un data frame cada vez y los resultados se convierten en una nueva columna de listas, a menudo con un modelo ajustado.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  group = c('A','A','A','B','B','B'),
  x = c(1,2,3,1,2,3),
  y = c(2.1,4.0,5.9,3.2,5.8,9.1)
)

models <- df %>%
  group_by(group) %>%
  nest() %>%
  mutate(model = map(data, ~lm(y ~ x, data = .x)))

print(models)

Extraer resultados de modelos con map()

Después de ajustar modelos por grupo, use map() con funciones como broom::tidy() o coef() para extraer los resultados de cada modelo. El resultado es otra columna de listas que posteriormente puede desanidarse.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  group = c('A','A','A','B','B','B'),
  x = c(1,2,3,1,2,3),
  y = c(2.1,4.0,5.9,3.2,5.8,9.1)
)

df %>%
  group_by(group) %>%
  nest() %>%
  mutate(
    model = map(data, ~lm(y ~ x, data = .x)),
    r_squared = map_dbl(model, ~summary(.x)$r.squared),
    intercept = map_dbl(model, ~coef(.x)[1]),
    slope = map_dbl(model, ~coef(.x)[2])
  ) %>%
  select(group, r_squared, intercept, slope)

unnest() — Expandir columnas de listas

unnest(df, cols = data) es la operación inversa de nest(). Expande la columna de listas para convertirla de nuevo en columnas normales y repite las columnas identificadoras cuando es necesario. Use cols para especificar qué columna de listas se desanidará.

library(tidyr)
library(dplyr)

nested <- data.frame(
  region = c('East','West')
)
nested$data <- list(
  data.frame(month=1:3, sales=c(100,120,110)),
  data.frame(month=1:2, sales=c(200,190))
)

unnested <- unnest(nested, cols = data)
print(unnested)

unnest_longer() — Expandir una lista en filas

unnest_longer(df, col) expande una columna de listas de modo que cada elemento de la lista se convierta en una fila. A diferencia de unnest(), que espera data frames, unnest_longer() funciona con listas de vectores o escalares.

library(tidyr)

df <- data.frame(
  person = c('Alice','Bob','Carol')
)
df$skills <- list(
  c('R','Python','SQL'),
  c('Excel','Tableau'),
  c('R','Julia','Stan','BUGS')
)

unnest_longer(df, skills)

unnest_wider() — Expandir una lista en columnas

unnest_wider(df, col) expande cada elemento de la lista en un conjunto de columnas nuevas. La lista debe tener elementos con nombres; esos nombres se convierten en nombres de columnas. Resulta útil para estructuras anidadas similares a JSON.

library(tidyr)

df <- data.frame(id = 1:3)
df$info <- list(
  list(name='Alice', age=30, city='NYC'),
  list(name='Bob', age=25, city='LA'),
  list(name='Carol', age=35, city='Chicago')
)

unnest_wider(df, info)

Patrón completo de trabajo con datos anidados

El flujo de trabajo completo con data frames anidados es: group_by() + nest() → aplicar funciones con map() → extraer los resultados → unnest() para volver a obtener un data frame plano. Este patrón permite ejecutar cualquier análisis por grupo.

library(tidyr)
library(dplyr)
library(purrr)

df <- data.frame(
  region = c('East','East','East','West','West','West'),
  month = c(1,2,3,1,2,3),
  revenue = c(100,120,115,200,195,210)
)

df %>%
  group_by(region) %>%
  nest() %>%
  mutate(
    mean_rev = map_dbl(data, ~mean(.x$revenue)),
    trend = map_dbl(data, ~coef(lm(revenue~month, data=.x))[2])
  ) %>%
  select(region, mean_rev, trend)

Anidar varias columnas

Puede seleccionar qué columnas se incluirán en el data frame anidado. Especifíquelas explícitamente en nest(data = c(...)). Las columnas no especificadas permanecen como columnas normales en el data frame externo, junto a la columna de listas.

library(tidyr)
library(dplyr)

df <- data.frame(
  region = c('East','East','West','West'),
  year = c(2023,2024,2023,2024),
  q1 = c(100,110,200,210),
  q2 = c(105,115,195,215),
  target = c(105,112,198,212)
)

# Only nest quarterly data, keep target as outer column
nested <- df %>%
  group_by(region, year) %>%
  nest(quarters = c(q1, q2))

print(nested)

Cuándo usar data frames anidados

Los data frames anidados son ideales cuando necesita ajustar el mismo modelo en distintos grupos, ejecutar simulaciones por grupo, aplicar transformaciones complejas a subconjuntos o trabajar con datos jerárquicos similares a JSON. Mantienen organizados los datos específicos de cada grupo junto a sus metadatos.

library(tidyr)
library(dplyr)
library(purrr)

# Bootstrap confidence interval per group
df <- data.frame(
  group = c('A','A','A','A','B','B','B','B'),
  value = c(10,12,11,13,20,22,19,21)
)

set.seed(42)
df %>%
  group_by(group) %>%
  nest() %>%
  mutate(
    boot_means = map(data, function(d) {
      replicate(100, mean(sample(d$value, replace=TRUE)))
    }),
    ci_low = map_dbl(boot_means, ~quantile(.x, 0.025)),
    ci_high = map_dbl(boot_means, ~quantile(.x, 0.975))
  ) %>%
  select(group, ci_low, ci_high)

Comprobación rápida

¿Cuál es la forma correcta de volver a expandir una columna de listas de data frames en un data frame plano?

Repaso: anidar y desanidar

Conceptos clave de los flujos de trabajo con data frames anidados:

  • nest(data = c(cols)) agrupa columnas en una columna de listas de data frames, uno por grupo
  • group_by() + nest() — el patrón estándar para anidar por grupo
  • map(nested$data, fn) — aplica cualquier función a cada data frame anidado
  • unnest(cols = data) — expande la columna de listas de data frames para volver al formato plano
  • unnest_longer(col) — expande una lista de vectores o escalares en filas
  • unnest_wider(col) — expande una lista con nombres en columnas
  • Es ideal para crear modelos por grupo, realizar bootstrap y procesar datos JSON
library(tidyr)
library(dplyr)
library(purrr)

data.frame(
  team = c('A','A','B','B'),
  x = c(1,2,1,2),
  y = c(2,4,3,6)
) %>%
  group_by(team) %>%
  nest() %>%
  mutate(
    model = map(data, ~lm(y ~ x, data = .x)),
    slope = map_dbl(model, ~coef(.x)['x'])
  ) %>%
  select(team, slope)

Preguntas frecuentes

¿La lección «Anidación y desanidación de data frames» es gratis?

Sí — el texto completo de «Anidación y desanidación de data frames» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de R Academy, actualiza a CoddyKit PRO. El curso de R Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Anidación y desanidación de data frames»?

Use nest() y unnest() para trabajar con list-columns en flujos de trabajo tidy. Practicas R Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar R Academy?

No se requiere experiencia previa. R Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Anidación y desanidación de data frames»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de R Academy?

Sí. Cada lección de R Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. De formato ancho a largo con pivot_longer()
  2. De formato largo a ancho con pivot_wider()
  3. separate() y unite() para columnas de cadenas
  4. Anidación y desanidación de data frames
← Volver a R Academy