如何在dplyr::case_when()中引用多列向量判断NA值?
基于多列NA判断创建新列的dplyr解决方案
问题背景
需要通过dplyr::case_when()生成新列:当指定子集的所有列均为NA时,新列值设为1,否则为0。但直接使用all(is.na(c(x,y)))的写法无法得到预期结果,示例代码及问题如下:
示例代码
test <- data.frame(x=c(1,2,3,NA,NA), y=c(1,NA,2,3,NA)) test %>% mutate(z = case_when( all(is.na(c(x,y))) ~ 1, .default = 0 ))
问题表现
预期第5行(x和y均为NA)的z值为1,其余行z值为0,但实际所有行的z值都为0。is.na(x) & is.na(y) ~ 1的写法虽可行,但不适用于列数较多的场景。
可行解决方案
针对多列场景,推荐两种高效写法:
方法1:结合rowwise()与c_across()
c_across()可选中指定范围的列,配合rowwise()实现逐行判断目标列是否全为NA:
test %>% rowwise() %>% mutate(z = case_when( all(is.na(c_across(c(x, y)))) ~ 1, .default = 0 )) %>% ungroup() # 完成操作后取消行分组,避免影响后续计算
支持tidyselect语法:选中连续列可写c_across(x:y),按列名模式匹配可写c_across(starts_with("col_"))。
方法2:使用if_all()
if_all()是dplyr 1.0.0+版本新增函数,可直接在case_when()中逐行判断指定列是否全部满足条件,无需手动分组:
test %>% mutate(z = case_when( if_all(c(x, y), is.na) ~ 1, .default = 0 ))
同样支持tidyselect语法,例如if_all(starts_with("x"), is.na)可选中所有以x开头的列。
原代码失效原因
原代码中all(is.na(c(x,y)))会将x、y整合成一个整体向量,判断整个向量是否全为NA,而非逐行判断每行的x和y是否都为NA,最终得到单一逻辑值FALSE,导致所有行的z值都为0。上述两种方法均针对每行的指定列做判断,符合需求。
内容的提问来源于stack exchange,提问作者JLinsta
相关产品推荐
相关产品推荐

