使用dplyr按条件生成Col3:仅拼接不含±的Name行
问题:使用dplyr根据Name列内容选择性拼接多列生成Col3
假设我们有如下的DataFrame(注意原始数据中存在重复的Col2列,实际读入后列名可能会自动调整为Col2和Col2.1,这里我们保持原始描述的列名逻辑):
df <- data.frame( Name = c("Wolf_+_", "Fox_-_", "Lezard_-_", "Elephant_-_", "AZ_89809", "Bear_+_", "ZA_08980", "TY_880DD2", "Snail_-_"), Col1 = c(NA, NA, NA, NA, "BOL", NA, "LUI", "IOP", NA), Col2 = c(NA, NA, NA, NA, "RAL", NA, "OPL", "MPO", NA), Col2 = c(NA, NA, NA, NA, "ZIL", NA, "YUI", "UII", NA), stringsAsFactors = FALSE )
需求是:
- 创建新列
Col3 - 仅对
Name中不含+或-的行,将Name、Col1、两个Col2列的值用|拼接 - 其余行(
Name含+或-)的Col3仅保留Name的值
当前使用的代码dplyr::mutate(df, Col3 = paste(Name, Col1, Col2, sep='|'))会对所有行进行拼接,不符合需求,期望的结果如下:
Name Col1 Col2 Col2 Col3 1 Wolf_+_ <NA> <NA> <NA> Wolf_+_ 2 Fox_-_ <NA> <NA> <NA> Fox_-_ 3 Lezard_-_ <NA> <NA> <NA> Lezard_-_ 4 Elephant_-_ <NA> <NA> <NA> Elephant_-_ 5 AZ_89809 BOL RAL ZIL AZ_89809|BOL|RAL|ZIL 6 Bear_+_ <NA> <NA> <NA> Bear_+_ 7 ZA_08980 LUI OPL YUI ZA_08980|LUI|OPL|YUI 8 TY_880DD2 IOP MPO UII TY_880DD2|IOP|MPO|UII 9 Snail_-_ <NA> <NA> <NA> Snail_-_
解决方案
我们可以结合dplyr::case_when()和stringr::str_detect()来实现条件逻辑,同时注意处理正则表达式中的特殊字符(+和-是正则元字符,需要用fixed()来匹配字面量):
library(dplyr) library(stringr) # 注意:如果原始数据的重复Col2列读入后列名为Col2.1,需要将代码中的第二个Col2改为Col2.1 df_result <- df %>% mutate( Col3 = case_when( # 判断Name中是否不包含+或- !str_detect(Name, fixed("+")) & !str_detect(Name, fixed("-")) ~ paste(Name, Col1, Col2, Col2, sep = "|"), # 其他情况直接返回Name TRUE ~ Name ) )
代码说明:
str_detect(fixed("+")):由于+和-是正则表达式中的特殊元字符,我们用fixed()来指定匹配字面量,避免正则规则干扰匹配结果case_when():这是dplyr中处理多条件分支的工具,第一个分支筛选出Name里既不含+也不含-的行,执行多列拼接;第二个TRUE分支兜底处理所有其他行,直接返回Name的值- 拼接列注意事项:原始数据存在重复的
Col2列,读入R后列名可能会被自动调整为Col2和Col2.1,如果遇到这种情况,记得把paste()里的第二个Col2改成Col2.1
运行上述代码后,就能得到你期望的结果。
内容的提问来源于stack exchange,提问作者Grendel




