为何在dplyr的summarize中对列表列使用c()不生效?
在dplyr summarize中按组合并列表列的问题解析
问题重现
想要在dplyr的summarize()中按组用c()合并列表列,预期每组返回一行,但实际得到多行结果并触发警告:
library(dplyr) df <- tibble::tibble(group = c("A", "A", "B"), list_col = list(list("One"), list("Two"), list("Three"))) df |> summarize(list_col = c(list_col), .by = group)
执行结果:
group list_col <chr> <list> 1 A <list [1]> 2 A <list [1]> 3 B <list [1]> Warning message: Returning more (or less) than 1 row per `summarise()` group was deprecated in dplyr 1.1.0. i Please use `reframe()` instead. i When switching from `summarise()` to `reframe()`, remember that `reframe()` always returns an ungrouped data frame and adjust accordingly. Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.
预期输出:
# A tibble: 2 × 2 group list_col <chr> <list> 1 A <list [2]> 2 B <list [1]> # 验证嵌套结构 output$list_col[[1]] [[1]] [1] "One" [[2]] [1] "Two"
为什么c()无法生效?
核心原因是dplyr的summarize()强制要求每个分组返回长度为1的结果:
- 单独执行
c(list("One"), list("Two"))会得到一个长度为2的列表; - 在分组A中调用
c(list_col)时,同样会生成长度为2的列表,但summarize()不允许每个分组返回长度>1的结果,因此会将这个结果拆分成两行输出,同时抛出警告提示改用reframe()(reframe()支持每组返回多行)。
你预期的是把合并后的列表作为一个单独的元素返回,但summarize()不会自动将长度>1的结果打包成单个列表元素,而是直接展开。
正确实现方法
要满足每组返回一行,同时保留嵌套列表结构,需要将c(list_col)的结果用list()包裹,让每个分组返回一个长度为1的列表元素(内部包含合并后的多个子列表):
df |> summarize(list_col = list(c(list_col)), .by = group)
执行结果与预期一致:
# A tibble: 2 × 2 group list_col <chr> <list> 1 A <list [2]> 2 B <list [1]>
验证嵌套结构:
result <- df |> summarize(list_col = list(c(list_col)), .by = group) result$list_col[[1]] # [[1]] # [1] "One" # # [[2]] # [1] "Two"
关于替代方案的说明
你之前使用的list(unlist(list_col))存在两个问题:
unlist()将嵌套列表转换为了字符向量,改变了原有的行级数据类型;- 无法保留原有的嵌套列表结构,而
list(c(list_col))则能完美保留嵌套结构,同时满足summarize()的要求。
内容的提问来源于stack exchange,提问作者LMc
相关产品推荐
相关产品推荐

