如何在pivot_wider中为布尔型列设置自定义列名?
问题
在使用tidyr::pivot_wider转换宽表时,当names_from参数包含布尔类型列时,默认生成的列名(如TRUE_foo、FALSE_bar)无法体现原布尔列的名称,缺乏辨识度。希望无需手动将布尔列转换为字符/因子型,而是通过pivot_wider的参数(如names_glue)实现自动识别布尔列并生成包含原列名的自定义列名(例如booTRUE_foo、booFALSE_foo)。
示例数据:
library(tidyverse) test_dat <- tibble( idx = c(rep("a", 6), rep("b", 6)), boo = c(rep(c(TRUE, FALSE), 6)), word = c(rep(c("foo", "bar", "baz"), 4)), val = runif(12) )
默认pivot_wider输出的列名无原布尔列标识,期望列名包含原布尔列名(如boo)+TRUE/FALSE+其他列名的格式。
解决方案
针对单个布尔列的简洁实现
如果names_from中只有一个布尔列,可以直接在names_glue中通过字符串拼接生成目标列名:
test_dat %>% pivot_wider( names_from = c(boo, word), values_from = val, names_glue = "{str_c('boo', boo)}_{word}" )
这里直接将布尔列名boo与它的取值(TRUE/FALSE)拼接,再和word列的值用下划线连接,直接得到booTRUE_foo这类符合要求的列名。
通用自动识别多布尔列的方案
如果names_from中有多个布尔列,或者不想硬编码布尔列名,可以写一个辅助函数自动识别列类型并生成列名:
# 定义列名生成函数:自动识别布尔列,拼接列名+值;非布尔列直接用值 build_col_name <- function(...) { input <- tibble(...) input %>% mutate(across(everything(), ~if_else(is.logical(.), str_c(cur_column(), .), as.character(.)))) %>% unite(col = "col_name", everything(), sep = "_") %>% pull(col_name) } # 应用到pivot_wider test_dat %>% pivot_wider( names_from = c(boo, word), values_from = val, names_glue = "{build_col_name(boo, word)}" )
这个函数会遍历names_from指定的所有列:
- 对布尔列:自动拼接列名+
TRUE/FALSE - 对非布尔列:直接保留原值
最后将所有部分用下划线连接,生成统一格式的列名,适配多布尔列场景。
输出示例
运行后得到的结果列名如下,数据内容与默认输出完全一致:
# A tibble: 2 × 7 idx booTRUE_foo booFALSE_bar booTRUE_baz booFALSE_foo booTRUE_bar booFALSE_baz <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> 1 a 0.325 0.770 0.824 0.351 0.555 0.698 2 b 0.0200 0.427 0.325 0.463 0.987 0.345
内容的提问来源于stack exchange,提问作者TY Lim
相关产品推荐
相关产品推荐

