2017-01-25 5 views
0

Допустим, мы должны data.frames:подмножество в data.frame на основе уникальных идентификаторов в другом data.frame

x <- data.frame(date=c(1,2,3,1,3), id=c("a", "a", "a", "b", "b"), sum=50:54) 
y <- data.frame(date=c(1,2,1,3), id=c("a", "a", "b", "b")) 

x 
    date id sum 
1 1 a 50 
2 2 a 51 
3 3 a 52 
4 1 b 53 
5 3 b 54 
y 

    date id 
1 1 a 
2 2 a 
3 1 b 
4 3 b 

Теперь я хочу, чтобы найти строку в х, имеет даты, не в y, в пределах одного и того же идентификатора. В y мы имеем 1, 2 и 3 в id a и в y имеем только 1 и 2 в id a. Как определить (и, желательно удалить из x) строку номер 3 в x?

EDIT: Я нашел (очень уродливое и медленное) решение, но должно быть лучше и быстрее? В настоящее время я запускаю его на двух больших data.frames, и первый раз это заняло более одного часа. Мне нужно запускать его несколько раз, поэтому любая помощь будет оценена по достоинству.

z <- data.frame() 

for (f in 1:length(unique(x$id))) { #Run the iteration for all the unique id's in x 
    id <- unique(x$id)[f] #find the name of the id in this iteriation 
    a <- x[x$id==id,]  #subset x 
    b <- y[y$id==id,]  #subset y 
x.new <- a[a$date%in%unique(b$date),] #find the dates that are in x and also in y 
z <- rbind(z, x.new)  #bind the two data.frames together 
} 

ответ

2

Кажется, что вы хотите внутреннее соединение. Вы концептуализируете проблему как «найдите строки в X, которые не находятся в Y, а затем удалите их из X», - это чаще всего указывается как «хранить только строки в X, которые также находятся в Y.»

Есть много способов сделать это, значение по умолчанию для base::merge

merge(x, y, all = F) 
# date id sum 
# 1 1 a 50 
# 2 1 b 53 
# 3 2 a 51 
# 4 3 b 54 

Есть много других вариантов, подробно описанных в R-FAQ How to join (merge) data frames (inner, outer, left, right)?

Если вам не нужно, чтобы идентифицировать удаленные строки для какой-либо другой цели, dplyr::anti_join - один из способов. anti_join(x, y) вернет строки в x, которые не находятся в y.

library(dplyr) 
anti_join(x, y) 
# Joining, by = c("date", "id") 
# date id sum 
# 1 3 a 52 

Если скорость является проблемой, метод data.table решения as in this answer будет быстрым. This answer does some fairly comprehensive benchmarking. Тем не менее, ваш код делает достаточно неэффективные шаги (рост кадра данных внутри цикла, пересчет тех же значений unique, иногда излишне), что, по моему мнению, даже base::merge будет на несколько порядков быстрее.

Смежные вопросы