0Pricing
R Academy · 课时

嵌套与展开数据框

使用 nest() 和 unnest() 处理整洁工作流中的列表列

嵌套与展开数据框 是 CoddyKit 上的免费 R Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。

列表列和嵌套数据

列表列是数据框中的一列,其中每个单元格都包含一个 R 对象(向量、数据框、模型或列表)。这样可以将结构化的子数据与其他列存放在一起,从而支持强大的分组工作流。

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() — 创建嵌套数据框

nest(df, data = c(col1, col2)) 按未嵌套的列对行进行分组,并将指定列打包到一个由数据框组成的列表列中。每个组占一行,每行包含一个小型数据框。

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() 与 group_by() 结合使用

最常见的模式是:先使用 group_by(),再使用 nest(),为每个组创建一行,并将其余所有列打包到 data 列表列中。在较新版本的 tidyr 中,这等价于 nest(.by = group_col)。

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() 处理嵌套数据框

数据嵌套后,可以使用 purrr::map() 对每个小型数据框应用函数。该函数每次接收一个数据框,处理结果会成为新的列表列,通常是一个拟合好的模型。

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)

使用 map() 提取模型结果

按组拟合模型后,可以将 map() 与 broom::tidy() 或 coef() 等函数结合使用,从每个模型中提取结果。输出会成为另一个列表列,之后可以将其展开。

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() — 展开列表列

unnest(df, cols = data) 是 nest() 的逆操作。它会将列表列展开为常规列,并根据需要重复标识列。使用 cols 指定要展开的列表列。

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() — 将列表展开为行

unnest_longer(df, col) 会展开列表列,使列表中的每个元素成为一行。与要求列表元素为数据框的 unnest() 不同,unnest_longer() 适用于由向量或标量组成的列表。

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() — 将列表展开为列

unnest_wider(df, col) 会将每个列表元素展开为一组新列。列表必须包含命名元素,这些名称会成为列名。它适用于类似嵌套 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)

完整的嵌套工作流模式

完整的嵌套数据框工作流为:group_by() + nest() → 使用 map() 应用函数 → 提取结果 → 使用 unnest() 恢复为扁平数据框。这种模式支持按组执行任意分析。

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)

嵌套多个列

您可以有选择地指定哪些列应放入嵌套数据框中。在 nest(data = c(...)) 中明确指定这些列。未指定的列会作为外层数据框中的常规列,与列表列并存。

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)

何时使用嵌套数据框

在以下场景中,嵌套数据框非常适用:对不同组拟合同一个模型、运行按组模拟、对数据子集应用复杂转换,或处理类似 JSON 的层次化数据。它们可以将组专属数据与组级元数据整齐地组织在一起。

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)

快速检查

如何将由数据框组成的列表列正确展开回扁平数据框?

总结:嵌套与展开

嵌套数据框工作流的要点:

  • nest(data = c(cols)) — 将列打包到由数据框组成的列表列中,每个组一个数据框
  • group_by() + nest() — 按组嵌套的标准模式
  • map(nested$data, fn) — 对每个嵌套数据框应用任意函数
  • unnest(cols = data) — 将由数据框组成的列表列展开回扁平格式
  • unnest_longer(col) — 将由向量或标量组成的列表展开为行
  • unnest_wider(col) — 将命名列表展开为列
  • 适用于按组建模、自助法和 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)

常见问题解答

「嵌套与展开数据框」课时是免费的吗?

是的 — 「嵌套与展开数据框」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。

「嵌套与展开数据框」这节课中我会学到什么?

使用 nest() 和 unnest() 处理整洁工作流中的列表列 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 R Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「嵌套与展开数据框」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 R Academy 课中编写并运行代码吗?

能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 使用 pivot_longer() 将宽格式转换为长格式
  2. 使用 pivot_wider() 将长格式转换为宽格式
  3. 使用 separate() 和 unite() 处理字符串列
  4. 嵌套与展开数据框
← 返回 R Academy