如何使用mutate、across与case_when实现符合条件的列名拼接
解决使用
across、case_when处理多列条件并生成拼接列名的问题 Great question! Let's break down your problems one by one and fix your code step by step.
你的三个问题解答
是否可以使用
across来检查多列的条件?
绝对可以!across就是dplyr专为批量处理多列设计的工具,不过要注意:默认情况下across会返回与输入列数相同的结果列,所以如果要生成单个新列,需要对across的输出做进一步的聚合处理,而不是直接赋值。case_when中如何获取对应的列名?
在across的函数里,你可以用cur_column()(dplyr 1.0.0+版本支持)或者.col参数(作为across的第二个参数传递)来获取当前处理的列名。比如当列值等于1时返回列名,否则返回NA_character_。如何只生成一个新列而不是多个?
不能直接把across的结果赋值给新列(因为across返回多列数据),需要用聚合函数(比如paste()结合na.omit())或者用purrr的工具(比如pmap_chr())把across返回的多列结果合并成单个字符串。
你的错误代码分析
你的原代码有几个关键问题:
df %>% rowwise() %>% mutate(New_Col = across(A1:A3, ~ case_when(. == 1 ~ paste0("colnames(.)", collapse = " "))))
colnames(.)中的.是当前列的值,不是列对象,所以无法获取列名;collapse = " "放在paste0()里无效,因为每个case_when只处理单个列的单个值,需要在所有列处理完成后再做拼接;- 直接把
across的结果赋值给New_Col,会让New_Col变成一个包含3个子列的列表列,而不是单个字符串列。
正确实现代码
这里提供两种简洁的实现方式,都能得到你期望的结果:
方法1:使用rowwise() + c_across()
这种方法直观易懂,适合新手:
library(dplyr) df <- tribble( ~ID, ~A1, ~A2, ~A3, 1, 0, 1, 1, 2, 0, 1, 1, 3, 1, 1, 1, 4, 1, 0, 1, 5, 0, 1, 0 ) df %>% rowwise() %>% # 筛选当前行值为1的列,拼接列名 mutate(New_Col = paste( names(select(., A1:A3))[c_across(A1:A3) == 1], collapse = " " )) %>% ungroup() # 记得取消行分组,避免后续操作变慢
方法2:使用across() + pmap_chr()
这种方法不需要行分组,效率更高:
df %>% mutate( New_Col = across(A1:A3, ~case_when(. == 1 ~ cur_column(), TRUE ~ NA_character_)) %>% pmap_chr(~paste(na.omit(c(...)), collapse = " ")) )
输出结果
两种方法都会得到你期望的结果:
# A tibble: 5 x 5 ID A1 A2 A3 New_Col <dbl> <dbl> <dbl> <dbl> <chr> 1 1 0 1 1 A2 A3 2 2 0 1 1 A2 A3 3 3 1 1 1 A1 A2 A3 4 4 1 0 1 A1 A3 5 5 0 1 0 A2
内容的提问来源于stack exchange,提问作者TarJae
相关产品推荐
相关产品推荐

