如何跨多个列匹配一列,以及 return 匹配新列中的 col_name

How to match a column across multiple columns and return matching col_name in a new column

假设我有一个数据集 df,其中我想在多个列 A to F 的值中匹配 col X 的值,并希望 return 匹配列名称(否则 NA ) 在新列中。

输入

df <- structure(list(A = c(4L, NA, NA, NA), B = c(NA, 5L, NA, NA), 
    C = c(NA, NA, NA, NA), D = c(NA, 4L, 6L, 7L), E = c(5L, NA, 
    NA, NA), F = c(NA, NA, NA, NA), X = 4:7), class = "data.frame", row.names = c(NA, 
-4L))

> df
   A  B  C  D  E  F X
1  4 NA NA NA  5 NA 4
2 NA  5 NA  4 NA NA 5
3 NA NA NA  6 NA NA 6
4 NA NA NA  7 NA NA 7

我想要的输出

> df_out
   A  B  C  D  E  F X new
1  4 NA NA NA  5 NA 4   A
2 NA  5 NA  4 NA NA 5   B
3 NA NA NA  6 NA NA 6   D
4 NA NA NA  7 NA NA 7   D

我更喜欢 dplyr/tidyverse 语法,我会将其集成到我现有的语法中。

一个选项可以是:

df %>%
 rowwise() %>%
 mutate(new = names(.)[which(c_across(-X) %in% X)])

      A     B C         D     E F         X new  
  <int> <int> <lgl> <int> <int> <lgl> <int> <chr>
1     4    NA NA       NA     5 NA        4 A    
2    NA     5 NA        4    NA NA        5 B    
3    NA    NA NA        6    NA NA        6 D    
4    NA    NA NA        7    NA NA        7 D

上面的解决方案假设列名对应于which()建立的位置。但是,如果不是这种情况(例如 c_across(-c(C, E, X)),则结果将不正确。更复杂情况的解决方案可能是:

df %>%
 mutate(new = Reduce(coalesce, across(-c(C, E, X), ~ ifelse(. == X, cur_column(), NA_character_))))
                          
   A  B  C  D  E  F X new
1  4 NA NA NA  5 NA 4   A
2 NA  5 NA  4 NA NA 5   B
3 NA NA NA  6 NA NA 6   D
4 NA NA NA  7 NA NA 7   D
df %>%
  pivot_longer(cols = -X) %>%
  mutate(
    match = if_else(X == value, name, NA_character_)
  ) %>%
  pivot_wider() %>%
  filter(!is.na(match))

A:F列与X列进行比较,将NA替换为FALSE并使用max.col获取[=17=的索引] 每行中的值,可用于获取列名。

library(dplyr)

df %>%
  mutate(new = {
    tmp <- select(., A:F) == X
    names(.)[max.col(replace(tmp, is.na(tmp), FALSE))]
  })

#   A  B  C  D  E  F X new
#1  4 NA NA NA  5 NA 4   A
#2 NA  5 NA  4 NA NA 5   B
#3 NA NA NA  6 NA NA 6   D
#4 NA NA NA  7 NA NA 7   D

在 base R 中,这可以写成:

tmp <- df[1:5] == df$X
df$new <- names(df)[max.col(replace(tmp, is.na(tmp), FALSE))]

此解决方案假设您在该行中至少有一个 X 的匹配项,如示例中所示。