R, выбирая все строки из фрейма данных, которые не отображаются в другом

Я пытаюсь решить сложную проблему R, которую я не смог решить с помощью ключевых слов Google. В частности, я пытаюсь взять подмножество одного фрейма данных, значения которого не отображаются в другом. Вот пример:

> test
      number    fruit     ID1  ID2 
item1 "number1" "apples"  "22" "33"
item2 "number2" "oranges" "13" "33"
item3 "number3" "peaches" "44" "25"
item4 "number4" "apples"  "12" "13"
> test2
      number    fruit     ID1   ID2 
item1 "number1" "papayas" "22"  "33"
item2 "number2" "oranges" "13"  "33"
item3 "number3" "peaches" "441" "25"
item4 "number4" "apples"  "123" "13"
item5 "number3" "peaches" "44"  "25"
item6 "number4" "apples"  "12"  "13"
item7 "number1" "apples"  "22"  "33"

У меня есть два кадра данных, test и test2, и цель состоит в том, чтобы выбрать все целые строки в test2, которые не отображаются в тесте, хотя некоторые из значений могут быть одинаковыми.

Результат, который я хочу, будет выглядеть так:

item1 "number1" "papayas" "22"  "33"
item2 "number3" "peaches" "441" "25"
item3 "number4" "apples"  "123" "13"

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

Я использовал подмножество R(), merge() и который() работает широко, но не мог понять, как использовать их в сочетании, если вообще возможно, получить то, что я хочу.

edit: Вот код R, который я использовал для создания этих двух таблиц.

test <- data.frame(c("number1", "apples", 22, 33), c("number2", "oranges", 13, 33),
    c("number3", "peaches", 44, 25), c("number4", "apples", 12, 13))

test <- t(test)
rownames(test) = c("item1", "item2", "item3", "item4")
colnames(test) = c("number", "fruit", "ID1", "ID2")

test2 <- data.frame(data.frame(c("number1", "papayas", 22, 33), c("number2", "oranges", 13, 33),
    c("number3", "peaches", 441, 25), c("number4", "apples", 123, 13),c("number3", "peaches", 44, 25), c("number4", "apples", 12, 13)  ))

test2 <- t(test2)
rownames(test2) = c("item1", "item2", "item3", "item4", "item5", "item6")
colnames(test2) = c("number", "fruit", "ID1", "ID2")

Спасибо заранее!

Ответ 1

Здесь другой способ:

x <- rbind(test2, test)
x[! duplicated(x, fromLast=TRUE) & seq(nrow(x)) <= nrow(test2), ]
#        number   fruit ID1 ID2
# item1 number1 papayas  22  33
# item3 number3 peaches 441  25
# item4 number4  apples 123  13

Изменить: изменено, чтобы сохранить имена строк.

Ответ 2

Существует два способа решить эту проблему, используя data.table и sqldf

library(data.table)
test<- fread('
item number fruit ID1 ID2 
item1 "number1" "apples"  "22" "33"
item2 "number2" "oranges" "13" "33"
item3 "number3" "peaches" "44" "25"
item4 "number4" "apples"  "12" "13"
')
test2<- fread('
item number fruit ID1 ID2 
item1 "number1" "papayas" "22"  "33"
item2 "number2" "oranges" "13"  "33"
item3 "number3" "peaches" "441" "25"
item4 "number4" "apples"  "123" "13"
item5 "number3" "peaches" "44"  "25"
item6 "number4" "apples"  "12"  "13"
item7 "number1" "apples"  "22"  "33"
')

data.table, это позволяет вам выбирать, какие столбцы вы хотите сравнить.

setkey(test,item,number,fruit,ID1,ID2)
setkey(test2,item,number,fruit,ID1,ID2)
test[!test2]
item  number   fruit ID1 ID2
1: item1 number1  apples  22  33
2: item3 number3 peaches  44  25
3: item4 number4  apples  12  13

Sql подход

sqldf('select * from test except select * from test2')
item  number   fruit ID1 ID2
1: item1 number1  apples  22  33
2: item3 number3 peaches  44  25
3: item4 number4  apples  12  13

Ответ 3

Ниже вы найдете следующее:

rows <- unique(unlist(mapply(function(x, y) 
          sapply(setdiff(x, y), function(d) which(x==d)), test2, test1)))
test2[rows, ]

Что здесь происходит:

  • mapply используется для сравнения по столбцам между двумя наборами данных.
  • Он использует setdiff для поиска любого элемента, который находится в первом, но не в последнем
  • which определяет, какая строка первого не существует.
  • unique(unlist(....)) захватывает все уникальные строки

  • Затем мы используем это как фильтр для первого, т.е. test2

Результаты:

       number   fruit ID1 ID2
item1 number1 papayas  22  33
item3 number3 peaches 441  25
item4 number4  apples 123  13

изменить:

Убедитесь, что ваши test и test2 являются data.frames, а не matrices, так как mapply выполняет итерацию по каждому элементу матрицы, но над каждым столбцом a data.frame

test  <- as.data.frame(test,  stringsAsFactors=FALSE)
test2 <- as.data.frame(test2, stringsAsFactors=FALSE)

Ответ 4

Создайте новый столбец идентификатора строки в test2, объедините кадры данных и выберите те строки, чьи идентификаторы не находятся в объединенном результате.

test2 <- cbind(test2, id=seq_len(nrow(test2)))

matches <- merge(test1, test2)$id

test2 <- test2[-matches, ]

Ответ 5

Здесь другой подход, но я не уверен, насколько он масштабируется.

test2[!apply(test2, 1, paste, collapse = "") %in% 
        apply(test, 1, paste, collapse = ""), ]
#       number    fruit     ID1   ID2 
# item1 "number1" "papayas" "22"  "33"
# item3 "number3" "peaches" "441" "25"
# item4 "number4" "apples"  "123" "13"

Это не приведет к удалению всех дубликатов. Сравните, например, если test2 имеет дубликаты:

test2 <- rbind(test2, test2[1:3, ])

## Matthew answer: Duplicates dropped
x <- rbind(test2, test)
x[! duplicated(x, fromLast=TRUE) & seq(nrow(x)) <= nrow(test2), ]
#       number    fruit     ID1   ID2 
# item4 "number4" "apples"  "123" "13"
# item1 "number1" "papayas" "22"  "33"
# item3 "number3" "peaches" "441" "25"

## This one: Duplicates retained
test2[!apply(test2, 1, paste, collapse = "") %in%
  apply(test, 1, paste, collapse = ""), ]
#       number    fruit     ID1   ID2 
# item1 "number1" "papayas" "22"  "33"
# item3 "number3" "peaches" "441" "25"
# item4 "number4" "apples"  "123" "13"
# item1 "number1" "papayas" "22"  "33"
# item3 "number3" "peaches" "441" "25"