удалить строки в фрейме данных R на основе группы и другого фрейма данных - PullRequest
0 голосов
/ 29 августа 2018

Есть два кадра данных

dat1 <- data.frame(group= c(11,11,12,12,13,13,14,14,15,15,16,16,17,17,17,18,18,18),name= c("A","B","C","D","E","F","G","H","I","J","A","B","E","F","W","A","B","V"))

dat2 <- data.frame(ID=c(1,1,2,2,3,3),name =c("A","B","E","F","X","Y"))

Второй кадр данных имеет комбинации двух значений, сгруппированных по столбцу идентификаторов. И основываясь на втором кадре данных (dat2), необходимо удалить строки в первой славе данных (dat1), если в dat2 существует конкретная комбинация групп.

Например: если «A» и «B» , оба существуют в dat1, а затем должны быть удалены.

Таким образом, желаемый результат равен

desiredat <- data.frame(group= c(12,12,13,13,15,15),name= c("C","D","G","H","I","J"))

Поиск путей в R для достижения того же.

Ответы [ 2 ]

0 голосов
/ 29 августа 2018

Это можно решить с помощью anti-join . Однако нам нужно определить, какие групповые идентификаторы group должны быть удалены из dat1.

library(data.table)
# count names per ID
setDT(dat2)[, n.id := .N, by = ID]
# identify groups to remove by joining and ... 
groups_to_remove <- dat2[setDT(dat1), on = "name", nomatch = 0L][
  # ... check which groups have a match with the complete set of names
  , which(n.id == .N), by = .(ID, group)]
# anti join
dat1[!groups_to_remove, on = "group"]
   group name
1:    12    C
2:    12    D
3:    14    G
4:    14    H
5:    15    I
6:    15    J
7:    19    A
8:    19    X

Группа 19 не удалена, поскольку имена «A» и «X» принадлежат разным идентификаторам в dat2.


Более упорядоченный подход использует all() вместо подсчета уникальных имен:

library(data.table)
setDT(dat1)
setDT(dat2)
groups_to_remove <- dat1[dat2, on = "name"][, which(all(ID == ID[1])), by = group]
dat1[!groups_to_remove, on = "group"]
   group name
1:    12    C
2:    12    D
3:    14    G
4:    14    H
5:    15    I
6:    15    J
7:    19    A
8:    19    X

То же, что и выше в синтаксисе dplyr:

library(dplyr)
dat2 %>% 
  left_join(dat1, by = "name") %>% 
  group_by(group) %>% 
  summarise(all_have_same_id = all(ID == ID[1L])) %>% 
  filter(all_have_same_id) %>% 
  anti_join(dat1, ., by = "group")
  group name
1    12    C
2    12    D
3    14    G
4    14    H
5    15    I
6    15    J
7    19    A
8    19    X
Warning message:
Column `name` joining factors with different levels, coercing to character vector

Данные

Образец набора данных dat1, предоставляемый OP, состоит из групп, в которых либо имя не включено в dat2, либо все имена имеют один идентификатор dat2 (возможно, плюс дополнительное имя), но в нем отсутствует сценарий использования. где только одно имя содержится в идентификаторе dat2. Поэтому я добавил этот вариант использования (как группа 19):

dat1 <- data.frame(
  group= c(11,11,12,12,13,13,14,14,15,15,16,16,17,17,17,18,18,18,19,19),
  name= c("A","B","C","D","E","F","G","H","I","J","A","B","E","F","W","A","B","V","A","X"))

dat2 <- data.frame(ID=c(1,1,2,2,3,3),name =c("A","B","E","F","X","Y"))
0 голосов
/ 29 августа 2018

Как то так ...?

dat1[dat1$name %in% setdiff(dat1$name, dat2$name), ]
3     12    C
4     12    D
7     14    G
8     14    H
9     15    I
10    15    J
15    17    W
18    18    V
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...