如何用purrr将分组分位数优雅转为数据框多列?
解决分组分位数转多列的问题
嘿,我懂你现在的困扰——把分组计算出来的分位数列表展开成单独的列,确实是用purrr时很常见的小卡点。我给你几个优雅的解决方案,总有一款适合你:
方法1:用unnest_wider()直接拆分列表列
这是最贴合你现有代码的方式,在你已经写好的nest+map代码后面,加上unnest_wider()就能把列表列里的向量直接拆成多列,还能自定义列名:
library(tidyverse) n <- 1000 toydata <- data.frame( sex = as.character(ifelse(rnorm(n)>0, "M", "F")), value = rnorm(n) ) p <- c(.1, .25, .5, .75, .9) # 给分位数设置清晰的列名,再拆分 toydata %>% group_by(sex) %>% nest() %>% mutate( # 先给每个分位数命名为q10、q25这种格式 quantiles = map(data, ~set_names(quantile(.$value, p, na.rm=TRUE), str_c("q", p*100))) ) %>% # 把列表列拆成多列 unnest_wider(quantiles) %>% # 不需要原始数据列的话可以删掉 select(-data)
运行后你会得到一个整洁的 tibble,每行对应一个性别,五列分别是q10到q90的分位数。
方法2:直接在map里返回tibble
如果你想一步到位生成可直接展开的结构,可以在map函数里直接返回一个tibble,这样后续用unnest()就能轻松展开:
toydata %>% group_by(sex) %>% nest() %>% mutate( quantiles = map(data, ~tibble( q10 = quantile(.$value, 0.1, na.rm=TRUE), q25 = quantile(.$value, 0.25, na.rm=TRUE), q50 = quantile(.$value, 0.5, na.rm=TRUE), q75 = quantile(.$value, 0.75, na.rm=TRUE), q90 = quantile(.$value, 0.9, na.rm=TRUE) )) ) %>% unnest(quantiles) %>% select(-data)
这种方法的好处是列名完全由你掌控,但如果分位数数量多的话会有点重复代码。
方法3:不用nest/map,直接用dplyr的summarize+across
如果你不需要保留原始分组数据的嵌套结构,这是最简洁的方法——直接用across函数对每个分位数概率批量计算:
toydata %>% group_by(sex) %>% summarize( # 对p里的每个概率计算分位数,自动生成q10、q25这样的列名 across(all_of(p), ~quantile(value, .x, na.rm=TRUE), .names = "q{.x*100}") )
一行代码搞定分组+计算+多列生成,完全不需要嵌套操作,非常高效!
内容的提问来源于stack exchange,提问作者gmason
相关产品推荐
相关产品推荐

