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 elementnest() — 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 datanest() 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 grupogroup_by() + nest()— el patrón estándar para anidar por grupomap(nested$data, fn)— aplica cualquier función a cada data frame anidadounnest(cols = data)— expande la columna de listas de data frames para volver al formato planounnest_longer(col)— expande una lista de vectores o escalares en filasunnest_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
- De formato ancho a largo con pivot_longer()
- De formato largo a ancho con pivot_wider()
- separate() y unite() para columnas de cadenas
- Anidación y desanidación de data frames