объединить два кадра данных на основе сопоставления двух заменяемых столбцов в каждом кадре данных - PullRequest
6 голосов
/ 25 мая 2011

У меня есть два данных в R.X и Y. Это НЕ парное сравнение, т.е. строка 1 (A = 1 B = 2) считается такой же, как строка 1 (X = 1, Y = 2) и строка 2 (X = 2, Y = 1) из dataframe 2.

Когда можно найти соответствие, я хотел бы добавить столбцы C, D, E, F dataframe1 обратно в соответствующую строку dataframe2 следующим образом: без соответствия как na.

Конечный фрейм данных

X Y Z C  D  E  F  G
1 2 g a  a  a  a  a 
2 1 h a  a  a  a  a
3 4 i na na na na na
1 4 j e  e  f  f  e

Я могу только знать, как выполнить сопоставление для одного столбца, однако как сделать сопоставление для двух заменяемых столбцов и объединить два кадра данных на основе результатов сопоставления трудномне.Просьба помочь предложить умный способ сделать это.

Для простоты обсуждения (спасибо за комментарии Винсента и DWin (мой предыдущий вопрос), что я должен проверить цитату.) Есть квота для загрузкикадры от 1 и 2 до R.

df1 <- data.frame(A = c(1,2,4), B=c(2,3,1), C=c('a','b','e'), 
                                D=c('a','b','e'), E=c('a','b','f'), 
                                F=c('a','c','f'), G=c('a','c', 'e'))

df2  <- data.frame(X = c(1,2,3,1), Y=c(2,1,4,4), Z=letters[7:10])

Ответы [ 5 ]

6 голосов
/ 25 мая 2011

Следующие работы, но без сомнения могут быть улучшены.

Сначала я создаю небольшую вспомогательную функцию, которая выполняет сортировку строк по A и B (и переименовывает ее в V1 и V2).

replace_index <- function(dat){
  x <- as.data.frame(t(sapply(seq_len(nrow(dat)), 
    function(i)sort(unlist(dat[i, 1:2])))))
  names(x) <- paste("V", seq_len(ncol(x)), sep="")
  data.frame(x, dat[, -(1:2), drop=FALSE])
} 

replace_index(df1)

  V1 V2 C D E F G
1  1  2 a a a a a
2  2  3 b b b c c
3  1  4 e e f f e

Это означает, что вы можете использовать прямое merge для объединения данных.

merge(replace_index(df1), replace_index(df2), all.y=TRUE)

  V1 V2    C    D    E    F    G Z
1  1  2    a    a    a    a    a g
2  1  2    a    a    a    a    a h
3  1  4    e    e    f    f    e j
4  3  4 <NA> <NA> <NA> <NA> <NA> i
1 голос
/ 25 мая 2011

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

# create id key to match
require(plyr)
df1 = adply(df1, 1, transform, id = paste(min(A, B),  "-", max(A, B)))
df2 = adply(df2, 1, transform, id = paste(min(X, Y),  "-", max(X, Y)))

# combine data frames using `match`
cbind(df2, df1[match(df2$id, df1$id),3:7])

Это производит вывод

X Y Z    id    C    D    E    F    G
1   1 2 g 1 - 2    a    a    a    a    a
1.1 2 1 h 1 - 2    a    a    a    a    a
NA  3 4 i 3 - 4 <NA> <NA> <NA> <NA> <NA>
3   1 4 j 1 - 4    e    e    f    f    e
1 голос
/ 25 мая 2011

Это немного неуклюже и имеет некоторые потенциальные проблемы с коллизиями и порядками, но работает с вашим примером

df1a <- df1; df1a$A <- df1$B; df1a$B <- df1$A #reverse A and B
merge(df2, rbind(df1,df1a), by.x=c("X","Y"), by.y=c("A","B"), all.x=TRUE)

для получения

  X Y Z    C    D    E    F    G
1 1 2 g    a    a    a    a    a
2 1 4 j    e    e    f    f    e
3 2 1 h    a    a    a    a    a
4 3 4 i <NA> <NA> <NA> <NA> <NA>
0 голосов
/ 23 апреля 2015

Вот еще одно возможное решение в базе R. Это решение cbind() новых ключевых столбцов (K1 и K2) для обоих data.frames с использованием векторизованных функций pmin() и pmax() для получения канонического порядкаиз ключевых столбцов и объединяет их:

merge(cbind(df2,K1=pmin(df2$X,df2$Y),K2=pmax(df2$X,df2$Y)),cbind(df1,K1=pmin(df1$A,df1$B),K2=pmax(df1$A,df1$B)),all.x=T)[,-c(1:2,6:7)];
##   X Y Z    C    D    E    F    G
## 1 1 2 g    a    a    a    a    a
## 2 2 1 h    a    a    a    a    a
## 3 1 4 j    e    e    f    f    e
## 4 3 4 i <NA> <NA> <NA> <NA> <NA>

Обратите внимание, что использование pmin() и pmax() возможно только для этой проблемы, поскольку у вас есть только два ключевых столбца;если бы у вас было больше, то вам пришлось бы использовать какое-то решение apply + sort для достижения канонического порядка ключей для слияния, аналогично тому, что делает @Andrie в своей вспомогательной функции, которая работала бы для любого числа ключевых столбцов, нобудет менее производительным.

0 голосов
/ 05 марта 2015

Вы также можете присоединиться к таблицам в обоих направлениях (X == A и Y == B, затем X == B и Y == A) и rbind их.Это приведет к дублированию пар, в которых один путь дал совпадение, а другой - NA, поэтому вы могли бы уменьшить дубликаты, разрезая только одну строку для каждой комбинации XY, одну без NA, если она существует.

library(dplyr)
m <- left_join(df2,df1,by = c("X" = "A","Y" = "B"))
n <- left_join(df2,df1,by = c("Y" = "A","X" = "B"))

rbind(m,n) %>%
  group_by(X,Y) %>%
  arrange(C,D,E,F,G) %>% # sort to put NA rows on bottom of pairs
  slice(1) # take top row from combination

Производит:

Source: local data frame [4 x 8]
Groups: X, Y

  X Y Z  C  D  E  F  G
1 1 2 g  a  a  a  a  a
2 1 4 j  e  e  f  f  e
3 2 1 h  a  a  a  a  a
4 3 4 i NA NA NA NA NA
...