2016-06-24 1 views
1

У меня есть два dataframes следующим образом,Сравнение двух data.frames с различными столбцами, чтобы найти строки в data.frame 1 отсутствует в других

a1 <- data.frame(a = 1:5, b=letters[1:5], c = 1:5) 
a2 <- data.frame(a = 1:3, b=letters[1:3], d = 1:3) 

Я хочу, чтобы найти строки a1 нет в a2 с только для первых двух столбцов (a, b). Мой идеальный выход должен быть,

a b c match 
1 1 a 1 yes 
2 2 b 2 yes 
3 3 c 3 yes 
4 4 d 4 no 
5 5 e 5 no 

Я попытался следующие,

output <- sqldf('SELECT * FROM a1 EXCEPT SELECT * FROM a2') 

, но это работает только тогда, когда есть равные колонки на обоих dataframes, а также имена одинаковы. Но я хочу найти только для совпадений в столбцах (a, b) и дать результат в a1 с да/нет.

Может ли кто-нибудь помочь мне найти это?

ответ

4

Мы можем сделать merge и найти NA значения от

c("no", "yes")[(!is.na(merge(a1, a2, by = c("a", "b"), all.x=TRUE)$d))+1L] 
#[1] "yes" "yes" "yes" "no" "no" 

Или без merge Инг, мы можем paste столбцы вместе и сделать сравнение с %in% и преобразовывают логично «да/нет»

c('no', 'yes')[(paste(a1$a, a1$b) %in% paste(a2$a, a2$b))+1] 
#[1] "yes" "yes" "yes" "no" "no" 

Или с помощью dplyr

library(dplyr) 
left_join(a1, a2, by = c("a", "b")) %>% 
      mutate(d = c("no", "yes")[(!is.na(d))+1]) 
# a b c d 
# 1 1 a 1 yes 
# 2 2 b 2 yes 
# 3 3 c 3 yes 
# 4 4 d 4 no 
# 5 5 e 5 no 
+0

@akun спасибо за это. У меня есть одно сомнение здесь. Если имена столбцов a2 (a, b) похожи на (q, w), мы можем дать следующее: c («нет», «да») [(! Is.na (слияние (a1, a2, by = c ("a" = "q", "b" = "w"), all.x = TRUE) $ d)) + 1L] – haimen

+0

@haimen В 'left_join', вы можете сделать этот синтаксис, но в 'merge', это будет' by.x' и 'by.y' – akrun

2

Используйте функцию row.match в библиотеке prodlim. Это возвращает вектор с числом совпадений (первое) и NA. Объедините это значение с ifelse, чтобы назначить да/нет.

library(prodlim) 
a1$match <- ifelse(is.na(row.match(a1, a2)), "no", "yes")  

# a b c match 
#1 1 a 1 yes 
#2 2 b 2 yes 
#3 3 c 3 yes 
#4 4 d 4 no 
#5 5 e 5 no 
+0

Plus. Разве это не обертка для 'paste/match' – akrun

+0

Спасибо. Основываясь на описании в руководстве, я бы сказал, что это так. – milan

1

Существует еще один вариант. Вы можете использовать функцию match_dfplyr.

library(plyr) 
a1$match <- ifelse(row.names(a1) %in% row.names(match_df(a1,a2)),"yes","no") 

Выход

a b c match 
1 1 a 1 yes 
2 2 b 2 yes 
3 3 c 3 yes 
4 4 d 4 no 
5 5 e 5 no 
Смежные вопросы