Это можно решить с помощью 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"))