R语言tidyverse如何简洁实现按列前缀嵌套tibble保留原列名
需求背景
常规nest()函数的嵌套逻辑是按行分组实现嵌套,本次需求与常规用法存在差异:
- 按照列名中第一个下划线
_前的前缀分组,创建嵌套tibble - 嵌套生成的子tibble需要保留原始列名
目前已通过多步转换实现需求,但代码逻辑过于繁琐,原有实现代码如下:
tibble(a_1=1:3, a_2=2:4, b_1=3:5) %>% print() %>% # A tibble: 3 x 3 # a_1 a_2 b_1 # <int> <int> <int> # 1 1 2 3 # 2 2 3 4 # 3 3 4 5 pivot_longer(everything()) %>% nest(data=-name) %>% mutate(data=map2(data, name, ~rename(.x, '{.y}' := value))) %>% mutate(gr=str_extract(name, '^[^_]+'), .keep='unused') %>% nest(data=-gr) %>% mutate(data=map(data, ~bind_cols(.[[1]]))) %>% print() %>% # A tibble: 2 x 2 # gr data # <chr> <list> # 1 a <tibble [3 x 2]> # 2 b <tibble [3 x 1]> { .$data[[1]] } # A tibble: 3 x 2 # a_1 a_2 # <int> <int> # 1 1 2 # 2 2 3 # 3 3 4
要求优先提供tidyverse风格的简洁解决方案。
tidyverse简洁实现
不需要做长宽表转换、反复嵌套重命名,直接按列名前缀匹配选列即可,逻辑更直白:
library(tidyverse) # 测试数据 df <- tibble(a_1=1:3, a_2=2:4, b_1=3:5) # 核心实现代码 nested_res <- tibble( # 提取所有不重复的列名前缀 gr = unique(str_extract(names(df), "^[^_]+")), # 按前缀匹配选择对应列,存入list列 data = map(gr, ~select(df, starts_with(paste0(.x, "_")))) )
运行后得到的结果和原有繁琐实现完全一致:
# A tibble: 2 × 2 gr data <chr> <list> 1 a <tibble [3 × 2]> 2 b <tibble [3 × 1]>
如果需要提取指定前缀对应的子tibble,直接索引即可,比如提取前缀a对应的子表:
nested_res$data[[1]]
输出结果:
# A tibble: 3 × 2 a_1 a_2 <int> <int> 1 1 2 2 2 3 3 3 4
方案优势
- 无冗余转换步骤:跳过了长宽表转换、多次嵌套、重命名、列合并等多余操作
- 天然保留原始列名:直接从原表选列,不需要额外做列名修复
- 可读性更强:代码逻辑和需求直接对应,先拿前缀,再按前缀选列,后续维护成本低
内容的提问来源于stack exchange,提问作者Sergey Skripko
相关产品推荐
相关产品推荐

