R语言中any函数跨多列执行逻辑运算结果异常及代码简化咨询
在R语言中简化多列多条件逻辑运算的问题
你遇到的核心问题是对any()函数的使用场景理解偏差——any()是对整个向量/矩阵返回单个逻辑值,而非按行逐行判断,这就导致改写后的代码会把全数据框是否存在1/-99的结果套用到所有行,自然和原代码的逐行判断逻辑不符。
先明确你的需求逻辑:
- 当
Participate(对应B1)<=2时,只要目标列(B2-B5或你实际用到的B1-B10+BOth)任意一列是1或-99,标记为"Noissue" - 当
Participate==3时,直接标记为"Noissue" - 其余情况标记为"Issue"
测试数据示例
| Participate | B1 | B2 | B3 | B4 | B5 | Query1 | Query2 |
|---|---|---|---|---|---|---|---|
| 3 | -1 | -1 | -1 | -1 | -1 | Noissue | Noissue |
| 1 | -1 | 1 | -1 | -1 | 1 | Noissue | Noissue |
| 1 | -1 | -1 | -1 | -1 | -1 | Issue | Noissue |
| 2 | -1 | 1 | 1 | -1 | 1 | Noissue | Noissue |
| 2 | 1 | 1 | 1 | 1 | -1 | Noissue | Noissue |
| 1 | -99 | -99 | -99 | -99 | -99 | Noissue | Noissue |
原可运行代码(Query1)
mutate(Batch_v1, case_when ( ((Batch_v1$B1 == 1 | Batch_v1$B2 == 1 | Batch_v1$B3 == 1 | Batch_v1$B4 == 1 | Batch_v1$B5 == 1| Batch_v1$B6 == 1| Batch_v1$B7 == 1|Batch_v1$B8 == 1|Batch_v1$B9 == 1|Batch_v1$B10 == 1|Batch_v1$BOth == 1) & Batch_v1$Participate %in% c(1,2,-99))~"Noissue", ((Batch_v1$B1 == -99 | Batch_v1$B2 == -99 | Batch_v1$B3 == -99|Batch_v1$B4 == -99 |Batch_v1$B5 == -99|Batch_v1$B6 == -99|Batch_v1$B7 == -99|Batch_v1$B8 == 1|Batch_v1$B9 == -99|Batch_v1$B10 == -99|Batch_v1$BOth == -99) & Batch_v1$Participate %in% c(1,2,-99))~"Noissue", Batch_v1$Participate ==3 ~ "Noissue", TRUE ~ "Issue" ))
改写后结果异常的代码(Query2)
mutate(Batch_v1, case_when ( ((any(Batch_v1[,2:6] == 1)) & Batch_v1$Participate %in% c(1,2,-99))~ "Noissue", ((any(Batch_v1[,2:6] == -99)) & Batch_v1$Participate %in% c(1,2,-99))~ "Noissue", Batch_v1$Participate ==3 ~ "Noissue", TRUE ~ "Issue" ))
解决方案:用if_any()实现逐行多列判断
从dplyr 1.0.0版本开始,官方提供了if_any()和if_all()函数,专门用于按行判断多列是否满足条件,完美匹配你的需求。
简洁实现代码:
library(dplyr) Batch_v1 %>% mutate( Query_correct = case_when( # 合并前两个条件:Participate符合要求,且任意目标列是1或-99 (if_any(B1:BOth, ~ .x %in% c(1, -99)) & Participate %in% c(1, 2, -99)) | Participate == 3 ~ "Noissue", TRUE ~ "Issue" ) )
代码解释:
if_any(B1:BOth, ~ .x %in% c(1, -99)):按行检查B1到BOth的所有列,只要任意一列的值是1或-99,该行返回TRUE- 结合
Participate %in% c(1,2,-99),就满足你前两个条件的逻辑 - 再加上
Participate ==3的条件,用|(或)合并,最后用case_when完成标记
低版本dplyr替代方案:
如果你的dplyr版本低于1.0.0,可以用rowwise()配合any()实现逐行判断:
Batch_v1 %>% rowwise() %>% mutate( has_1_or_neg99 = any(c_across(B1:BOth) %in% c(1, -99)), Query_correct = case_when( (has_1_or_neg99 & Participate %in% c(1,2,-99)) | Participate ==3 ~ "Noissue", TRUE ~ "Issue" ) ) %>% ungroup()
这样写出来的代码不仅简洁,而且逻辑和原代码完全一致,测试数据中的第三行也会正确标记为"Issue"。
内容的提问来源于stack exchange,提问作者Mohana
相关产品推荐
相关产品推荐

