R Найти строку, совпадающую с несколькими столбцами, и выбрать наиболее подходящее соответствие столбцов - PullRequest
0 голосов
/ 01 марта 2019

У меня есть проблема, для которой я не могу найти решение. Вот некоторые примеры данных:

df<-data.frame(ID1=c("A10","B73","B73","D20"),
               ID2=c(NA,"B4","C05","D100"),
               ID3=c(NA,"B20","C30","D41"),
               ID4=c(NA,NA,"B40","D0"),
               ID5=c(NA,NA,NA,"D10"),
               Score=c(15,376,102,30))
>df
  ID1  ID2  ID3  ID4  ID5 Score
1 A10 <NA> <NA> <NA> <NA>    15
2 B73   B4  B20 <NA> <NA>   376
3 B73  C05  C30  B40 <NA>   102
4 D20 D100  D41   D0  D10    30

У меня также есть данные с разными идентификационными номерами, которые соответствуют некоторым из ID 's в df и соответствует Score.Это выглядит следующим образом:

df_match<-data.frame(ID_Match=c("A10","B4","B20","E20","A355","D0","C30"),
               Score_Match=c(30,55,200,120,113,23,98))
>df_match
  ID_Match Score_Match
1      A10          30
2       B4          55
3      B20         200
4      E20         120
5     A355         113
6       D0          23
7      C30          98

Я хочу, чтобы R выполнял поиск совпадений идентификаторов в df, и если есть совпадение, поместите соответствующее ID en Score вновый столбец.Если в одной строке содержится несколько совпадений идентификаторов, выберите совпадение идентификаторов самого правого столбца.Так бы это выглядело так:

> df_Final
  ID1  ID2  ID3  ID4  ID5 Score ID_Match Score_Match
1 A10 <NA> <NA> <NA> <NA>    15      A10          30
2 B73   B4  B20 <NA> <NA>   376      B20         200
3 B73  C05  C30  B40 <NA>   102      C30          98
4 D20 D100  D41   D0  D10    30       D0          23

Я нашел ответы вроде:

IDColumns <- 1:5
d <- df[,IDColumns] == "ID"

или

df$Check <- (rowSums(df[,startsWith(names(df),"ID")]=="ID") >= 1)

Но большинство ответов, которые я нашел, искал толькосовпадение одной конкретной строки.Может ли кто-нибудь помочь мне?

Ответы [ 2 ]

0 голосов
/ 01 марта 2019

Сначала будет полезна соответствующая матрица.

MX <- t(apply(df[, -6], 1, function(x) x %in% df_match$ID_Match))

#       [,1]  [,2]  [,3]  [,4]  [,5]
# [1,]  TRUE FALSE FALSE FALSE FALSE
# [2,] FALSE  TRUE  TRUE FALSE FALSE
# [3,] FALSE FALSE  TRUE FALSE FALSE
# [4,] FALSE FALSE FALSE  TRUE FALSE

Теперь нам нужен «самый правый столбец», где мы можем использовать sum().

idx <- apply(MX, 1, function(x) {
  if (sum(x) > 1)
    tail(which(x == TRUE), 1)
  else if (sum(x) == 1)
    which(x == TRUE)
  else NA
})

В концепросто cbind() соответствующие значения, используя %in%.

res <- cbind(df, 
             df_match[which(df_match$ID_Match %in% 
                              sapply(1:nrow(df), function(x) df[x, idx[x]])), ])

Результат

> res
  ID1  ID2  ID3  ID4  ID5 Score ID_Match Score_Match
1 A10 <NA> <NA> <NA> <NA>    15      A10          30
3 B73   B4  B20 <NA> <NA>   376      B20         200
6 B73  C05  C30  B40 <NA>   102       D0          23
7 D20 D100  D41   D0  D10    30      C30          98
0 голосов
/ 01 марта 2019

Я не уверен, работает ли это при каких-либо обстоятельствах, но, возможно, это все еще помогает

    df<-data.frame(ID1=c("A10","B73","B73","D20"),
               ID2=c(NA,"B4","C05","D100"),
               ID3=c(NA,"B20","C30","D41"),
               ID4=c(NA,NA,"B40","D0"),
               ID5=c(NA,NA,NA,"D10"),
               Score=c(15,376,102,30))


df_match<-data.frame(ID_Match=c("A10","B4","B20","E20","A355","D0","C30"),
                     Score_Match=c(30,55,200,120,113,23,98))

# create backup for the results
df2 = df

# create a dummy-column as an "ID" for each row
df$rownumber = 1:NROW(df)

# convert Data to longformat and get rid of all those IDs, that are NA
df = reshape2::melt(df, measure.vars = names(df)[which(names(df) != "rownumber")], id.vars = "rownumber", na.rm = T)
df %>% arrange(rownumber)

# find the matching scores for all IDs left
df = merge(df, df_match, by.x = "value", by.y = "ID_Match", all.x = T)
# remove all ids, that didn't have a match in df_match
df = df %>% filter(!is.na(Score_Match))
# remove the substring ID from each ID-Variable, so we can use it as a numeric
df$variable = as.numeric(as.character(gsub("ID", "", df$variable)))

# now lets select the ID most far right. Its the one with the highest ID<Number>
df = df %>% group_by(rownumber) %>% filter(variable == max(variable)) %>% arrange(rownumber)

# attach the data to the original file
df2$ID_Match = df$value
df2$score_Match = df$Score_Match
df2

# > df2
#   ID1  ID2  ID3  ID4  ID5 Score ID_Match score_Match
# 1 A10 <NA> <NA> <NA> <NA>    15      A10          30
# 2 B73   B4  B20 <NA> <NA>   376      B20         200
# 3 B73  C05  C30  B40 <NA>   102      C30          98
# 4 D20 D100  D41   D0  D10    30       D0          23

, это может создать проблемы, если есть строки, которые не соответствуют ни по одному из идентификаторов.В этом случае добавление df2 $ rownumber = 1: NROW (df2) и сопоставление df с df2 по rownumber вместо прямого присоединения может помочь (я надеюсь:))

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...