R语言tidyverse如何仅当分组无NA时判断组内是否存在值4
实现方案
你可以通过批量遍历分组前缀的方式实现需求,仅需少量代码即可适配任意数量的分组,无需手动逐个定义变量或生成中间标记列:
如果你的分组前缀是已知的,可以直接定义前缀列表:
library(tidyverse) # 示例数据和你提供的一致 df <- data.frame(Subj = c("A", "B", "C", "D"), Happy_1_Num = c(4,2,2,NA), Happy_2_Num = c(4,2,2,1), Happy_3_Num = c(1,NA,2,4), Sad_1_Num = c(2,1,4,3), Sad_2_Num = c(NA,1,2,4), Sad_3_Num = c(4,2,2,1)) # 定义所有需要处理的分组前缀 group_prefix <- c("Happy", "Sad") # 一步生成所有新变量 df <- df %>% mutate( across(all_of(group_prefix), ~ case_when( # 分组内任意变量为NA则返回NA if_any(matches(paste0("^", cur_column(), "_.*_Num$")), is.na) ~ NA_real_, # 分组内任意变量为4则返回1 if_any(matches(paste0("^", cur_column(), "_.*_Num$")), ~.x == 4) ~ 1, # 其余情况返回0 .default = 0 ), # 新变量命名规则 .names = "{.col}_Any4") )
如果你的分组数量多、前缀不固定,可以自动从列名提取所有符合规则的前缀,无需手动填写:
# 自动提取所有符合 前缀_数字_Num 格式的列的前缀 group_prefix <- str_extract(names(df), "^.*(?=_[0-9]+_Num$)") %>% na.omit() %>% unique() # 后续和上面的mutate代码完全一致 df <- df %>% mutate( across(all_of(group_prefix), ~ case_when( if_any(matches(paste0("^", cur_column(), "_.*_Num$")), is.na) ~ NA_real_, if_any(matches(paste0("^", cur_column(), "_.*_Num$")), ~.x == 4) ~ 1, .default = 0 ), .names = "{.col}_Any4") )
结果验证
运行后生成的Happy_Any4和Sad_Any4结果如下,完全符合规则要求:
| Subj | Happy_Any4 | Sad_Any4 |
|---|---|---|
| A | 1 | NA |
| B | NA | 0 |
| C | 0 | 1 |
| D | NA | 1 |
原代码问题说明
最初的写法逻辑本身没有错误,问题出在多条件matches的兼容性上,部分dplyr版本对matches(A) & matches(B)的支持不稳定,合并为单个正则表达式matches("^前缀_.*_Num$")即可解决,配合批量遍历的写法可以大幅减少重复代码。
内容的提问来源于stack exchange,提问作者Emma Loke
相关产品推荐
相关产品推荐

