在 case_when 中使用列名作为失败输出

Using a column name as a fail output in case_when

我正在比较从一组文件中提取的几列 ID 变量与主列表,这些 ID 应该跨列匹配。我正在使用 case_when 来确保它们都符合主列表,但我想知道是否有一种方便的方法可以将“TRUE ~”输出更改为未通过测试的值的列名?

这是基本要点,

a <- c(1,2,3,4)
b <- c(1,2,3,4)
c <- c(1,2, "NA", "NA")
d <- c(1,2,3,4)

example <- data.table(a,b,c,d)

example %>% mutate(
   test = case_when(
      a==b & a==c & a==d ~ "PASS",
   TRUE ~ "FAIL")
)

这将完成标记任何未通过测试的值的基本工作,但是是否有一种模块化方法可以将 TRUE ~ "FAIL" 输出更改为产生失败的列的名称,"c" in这种情况?

library(dplyr)

example %>% 
  rowwise() %>% 
  dplyr::mutate(cond = cond = names(example)[which(!replace_na(a == c_across(b:d), F)) + 1] %>% 
                  paste(collapse = ",")) %>% 
  ungroup()

注:+ 1是因为这个按索引查找列名没有通过。 + 1 是跳过第 a 列,以便 cond 显示正确的列。 paste用于有多个不满足条件的列。它们将在 cond.

中以逗号分隔

另外正如@r2evans 在关于强制的评论中提到的,我将 c <- c(1,2, "NA", "NA") 修改为 c <- c(1,2, NA, NA)

输出

      a     b     c     d cond 
  <dbl> <dbl> <dbl> <dbl> <chr>
1     1     1     1     1 ""   
2     2     2     2     2 ""   
3     3     3    NA     3 "c"  
4     4     4    NA     4 "c" 

多列失败条件

a <- c(1,2,3,4)
b <- c(1,2,3,4)
c <- c(1,2, NA, NA)
d <- c(1,2,3,6)

example <- data.frame(a,b,c,d)

example %>% 
  rowwise() %>% 
  dplyr::mutate(cond = cond = names(example)[which(!replace_na(a == c_across(b:d), F)) + 1] %>% 
                  paste(collapse = ",")) %>% 
  ungroup()

      a     b     c     d cond 
  <dbl> <dbl> <dbl> <dbl> <chr>
1     1     1     1     1 ""   
2     2     2     2     2 ""   
3     3     3    NA     3 "c"  
4     4     4    NA     6 "c,d"

将向量存储在数据框中并使用 sapply 可行:

a <- c(1,2,3,4)
b <- c(1,2,3,4)
c <- c(1,2, "NA", "NA")
d <- c(1,2,3,4)
df <- data.frame(a,b,c,d)

result <- sapply(2:4, function(x) identical(df$a, df[, x]))
result
[1]  TRUE FALSE  TRUE

您可以根据实际数据框的尺寸调整 sapply 中的参数。您还可以 rbind resultdf 并为列 a:

插入虚拟值
result <- c(999, result)
df <- rbind(result, df)
df
    a b  c d
1 999 1  0 1
2   1 1  1 1
3   2 2  2 2
4   3 3 NA 3
5   4 4 NA 4

为了类型的完整性,逻辑值 result 被转换为整数。结果行中的零表示哪些列未通过测试。