Объединить на x1, или если нет совпадения x2, или если нет совпадения x3 - PullRequest
0 голосов
/ 03 октября 2018

Я пытаюсь объединить 2 набора данных на ключе, но если совпадений нет, я хочу попробовать другой ключ и т. Д.

df1 <- data.frame(a=c(5,1,7,3),
              b=c("T","T","T","F"),
              c=c("F","T","F","F"))


df2 <- data.frame(x1=c(4,5,3,9), 
                  x2=c(7,8,1,2),
                  x3=c("g","w","t","o"))
df1
   a  b  c
1  5  T  F
2  1  T  T
3  7  T  F
4  3  F  F

df2
   x1 x2 x3 ..
1  4  7  g  ..
2  5  8  w  ..
3  3  1  t  ..
4  9  2  o  ..

Требуемый вывод похож на

   a  b  c x3  ..
1  5  T  F  w  ..
2  1  T  T  t  ..
3  7  T  F  g  ..
4  3  F  F  t  ..

Я пробовал что-то вроде

dfm <- merge(df1,df2, by.x = "a", by.y = "x1", all.x = TRUE)
dfm <- merge(dfm,df2, by.x = "a", by.y = "x2", all.x = TRUE)

, но это не совсем так.

Ответы [ 4 ]

0 голосов
/ 04 октября 2018

Не уверен, что понял ваш вопрос, но вместо повторного слияния я бы сравнил ключи потенциального слияния, если это число> 0, чем у вас совпадение.Если вы хотите взять первый столбец с соответствием, вы можете попробовать это:

    library(tidyr)
    library(purrr)
    (df1 <- data.frame(a=c(5,1,7,3),
          b=c("T","T","T","F"),
          c=c("F","T","F","F")) )
    (df2 <- data.frame(x1=c(4,5,3,9), 
              x2=c(7,8,1,2),
              x3=c("g","w","t","o")) )

     FirstColMatch<-1:ncol(df2) %>% 
         map(~intersect(df1$a, df2[[.x]])) %>% 
         map(length)  %>%
         detect_index(function(x)x>0)

     NewDF<-merge(df1,df2,by.x="a", by.y =names(df2)[FirstColMatch])
0 голосов
/ 03 октября 2018

Вы можете сделать что-то вроде этого:

matches <- lapply(df2[, c("x1", "x2")], function(x) match(df1$a, x))
# finding matches in df2$x1 and df2$x2
# notice that the code below should work with any number of columns to be matched:
# you just need to add the names here eg. df2[, paste0("x", 1:100)] 
matches
$x1
[1]  2 NA NA  3

$x2
[1] NA  3  1 NA
combo <- Reduce(function(a,b) "[<-"(a, is.na(a), b[is.na(a)]), matches)
# combining the matches on "first come first served" basis
combo
[1] 2 3 1 3
cbind(df1, df2[combo,])
    a b c x1 x2 x3
2   5 T F  5  8  w
3   1 T T  3  1  t
1   7 T F  4  7  g
3.1 3 F F  3  1  t
0 голосов
/ 04 октября 2018

Если я правильно понимаю, ОП запросил сначала попытку сопоставления a с x1, а затем - если не удалось - попытаться сопоставить a с x2.Поэтому любое совпадение a с x1 должно иметь приоритет над совпадением a с x2.

К сожалению, примерный набор данных, предоставленный OP, не не включить случай использования, чтобы доказать это.Поэтому я соответственно изменил образец набора данных (см. Раздел Данные ).

Предлагаемый здесь подход заключается в изменении формы df2 из широкого в длинный формат (аналогично ответу MrFlick), но для использования data.table объединения с параметром mult = "first".

Столбцы df2, которые следует рассматривать как ключевые столбцы , и приоритет можно контролировать с помощью параметра measure.vars для melt().После изменения формы melt() упорядочивает строки в порядке столбцов, заданном в measure.vars:

library(data.table)
# define cols of df2 to use as key in order of 
key_cols <- c("x1", "x2")
# reshape df2 from wide to long format
long <- melt(setDT(df2), measure.vars = key_cols, value.name = "a")
# join long with df1, pick first matches
result <- long[setDT(df1), on = "a", mult = "first"]
# clean up
setcolorder(result, names(df1))
result[, variable := NULL]
result
   a b c   x3
1: 5 T F    w
2: 1 T T    t
3: 7 T F    g
4: 3 F F    t
5: 0 F F <NA>

Обратите внимание, что исходный порядок строк df1 имеетбыли сохранены.

Также обратите внимание, что код работает для произвольного числа ключевых столбцов.Приоритет ключевых столбцов может быть легко изменен.Например, если порядок обратный, т. Е. Сначала будет выбрано key_cols <- c("x2", "x1") совпадений a с x2.

Данные

Расширенные образцы наборов данных:

У df1 есть дополнительная строка без совпадения в df2.

df1 <- data.frame(a=c(5,1,7,3,0),
                  b=c("T","T","T","F","F"),
                  c=c("F","T","F","F","F"))
df1
   a b c
1: 5 T F
2: 1 T T
3: 7 T F
4: 3 F F
5: 0 F F

df2 имеет дополнительную строку, чтобы доказать, что совпадение в x1 имеет приоритет над совпадением в x2.Значение 5 появляется дважды: в строке 2 столбца x1 и в строке 5 столбца x2.

df2 <- data.frame(x1=c(4,5,3,9,6), 
                  x2=c(7,8,1,2,5),
                  x3=c("g","w","t","o","n"))
df2
   x1 x2 x3
1:  4  7  g
2:  5  8  w
3:  3  1  t
4:  9  2  o
5:  6  5  n
0 голосов
/ 03 октября 2018

Это действительно не стандартное слияние.Вы можете сделать его более стандартным, изменив df2, чтобы у вас было только одно поле для объединения на

df2long <- rbind(
    data.frame(a = df2$x1, df2[,-(1:2), drop=FALSE]), 
    data.frame(a = df2$x2, df2[,-(1:2), drop=FALSE])
)
dfm <- merge(df1, df2long, by = "a", all.x = TRUE)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...