输出值与 R 中的特定数字匹配的所有列名

Output all column names where the value matches a specific number in R

我有一个关于患者是否符合研究标准的数据框,每一行是一个患者,每一列是一个标准。所以有些列是纳入标准,有些列是排除标准,我想输出不合格的原因。例如,

test <- data.frame(A = c(0, 0, 1), 
                   B = c(0, 0, 0), 
                   C = c(0, 1, 1), 
                   D = c(1, 0, 0), 
                   E = c(1, 0, 1))

其中 A、B、C 是包含标准,D、E 是排除标准,如果包含标准 == 0 或排除标准 == 1,我想输出列名(可能不止一个) .

预期输出为

output <- data.frame(A = c(0, 0, 1), 
                       B = c(0, 0, 0), 
                       C = c(0, 1, 1), 
                       D = c(1, 0, 0), 
                       E = c(1, 0, 1),
                       failed_incl = c("A, B, C", "A, B", "B"),
                       failed_excl = c("D, E", "", "E"))

有没有一种方法可以高效地做到这一点而不必写出所有可能的场景?实际数据框有更多的列。

有多种方式。一种选择是使用 apply 遍历行 (MARGIN = 1),将逻辑向量 (x== 0) 的 namespaste 放在一起

test$failed_incl <- apply(test[1:3], 1, function(x) toString(names(x)[x == 0]))
test$failed_excl <- apply(test[4:5], 1, function(x) toString(names(x)[x == 1]))

-输出

test
#  A B C D E failed_incl failed_excl
#1 0 0 0 1 1     A, B, C        D, E
#2 0 0 1 0 0        A, B            
#3 1 0 1 0 1           B           E

或使用tidyverse

library(dplyr)
test %>%
    rowwise %>% 
    mutate(failed_incl = toString(names(.)[which(c_across(A:C) == 0)]),
           failed_excl = toString(c('D', 'E')[which(c_across(D:E) == 1)])) %>% 
    ungroup
# A tibble: 3 x 7
#      A     B     C     D     E failed_incl failed_excl
#  <dbl> <dbl> <dbl> <dbl> <dbl> <chr>       <chr>      
#1     0     0     0     1     1 A, B, C     "D, E"     
#2     0     0     1     0     0 A, B        ""         
#3     1     0     1     0     1 B           "E"    

这里有一个 tidyverse 方法,它旋转列名,然后根据 inclusion/exclusion 条件进行汇总:

failed_df <-
  test %>%
  add_rownames() %>%
  pivot_longer(-rowname) %>%
  group_by(rowname) %>%
  summarise(failed_incl = paste(name[value == 0 & name %in% c("A", "B", "C")], collapse = ", "),
            failed_excl = paste(name[value == 1 & name %in% c("D", "E")], collapse = ", ")) %>%
  select(-rowname)

bind_cols(test, failed_df)

  A B C D E failed_incl failed_excl
1 0 0 0 1 1     A, B, C        D, E
2 0 0 1 0 0        A, B            
3 1 0 1 0 1           B           E

rowwisec_across 可能有更优雅的方法。