为何purrr的map_dfc与map_dfr在dplyr summarise中输出一致?
问题原因及解决方法
核心问题
你碰到的问题根源在于dplyr::summarise()的设计逻辑:它要求每个汇总表达式返回的结果长度必须和分组数一致(每组对应1个结果)。当你在summarise()里直接用map_dfr()时,它生成的多行数据框会被summarise()当成单个列表元素存起来,而不是展开成行;而map_dfc()生成的多列数据框会被summarise()直接拆成列,这就导致两者输出看起来一样,但map_dfr()的结果其实是嵌套的列表列,没发挥出行绑定的作用。
正确实现方式
要实现按行绑定并保留迭代追踪的需求,得绕开summarise()的单值限制,推荐两种方法:
方法1:group_map() + bind_rows()
直接对分组数据做映射,合并时自动保留分组信息:
library(dplyr) library(purrr) # 示例:按气缸数分组,计算mpg的10%、20%分位数,保留分位数类型 mtcars %>% group_by(cyl) %>% group_map(function(group_data, group_info) { map_dfr(c(10, 20), function(p) { tibble( cyl = group_info$cyl, percentile = paste0(p, "%"), mpg_quantile = quantile(group_data$mpg, p/100) ) }) }) %>% bind_rows()
方法2:嵌套数据框 + map_dfr()
先把分组数据嵌套成列表列,再映射处理后展开:
mtcars %>% group_by(cyl) %>% nest() %>% mutate( quant_results = map(data, function(df) { map_dfr(c(10, 20), ~tibble(percentile = paste0(.x, "%"), mpg_quantile = quantile(df$mpg, .x/100)), .id = "iter_id") }) ) %>% unnest(quant_results) %>% select(-data)
错误写法对比
你之前在summarise()里用map_dfr()的写法,会把多行结果打包成列表列,表面和map_dfc()的列结构类似,但实际是嵌套的:
# 错误写法示例 wrong_output <- mtcars %>% group_by(cyl) %>% summarise( map_output = map_dfr(c(10, 20), ~tibble(mpg_quantile = quantile(mpg, .x/100)), .id = "percentile"), .groups = "drop" ) # 查看结构就能发现map_output是列表列 str(wrong_output$map_output)
总结
summarise()的定位是每组返回单个值或单行数据,不适合生成多行结果- 要生成按行绑定的多组迭代结果,优先用
group_map()配合bind_rows(),或者嵌套后映射展开 map_dfr()的.id参数只有在直接合并数据框时才会生效,被summarise()包裹时会失效
内容的提问来源于stack exchange,提问作者Stefan
相关产品推荐
相关产品推荐

