如何根据属于另一个向量的一个向量合并向量列表?

Luc*_*ion 5 merge r list data.table

在R中,我有两个包含列表列的数据框

d1 <- data.table(
  group_id1=1:4
)
d1$Cat_grouped <- list(letters[1:2],letters[3:2],letters[3:6],letters[11:12] )
Run Code Online (Sandbox Code Playgroud)

d_grouped <- data.table(
  group_id2=1:4
)
d_grouped$Cat_grouped <- list(letters[1:5],letters[6:10],letters[1:2],letters[1] )
Run Code Online (Sandbox Code Playgroud)

我想合并这两个data.tables基于d1$Cat_grouped包含在向量中的向量d_grouped$Cat_grouped

更确切地说,可能有两个匹配标准:

a)每个向量的所有元素d1$Cat_grouped必须在匹配的向量中d_grouped$Cat_grouped

导致以下匹配:

result_a <- data.table(
   group_id1=c(1,2)
   group_id2=c(1,1)
)
Run Code Online (Sandbox Code Playgroud)

b)每个向量中的至少一个元素d1$Cat_grouped必须在匹配的向量中d_grouped$Cat_grouped

导致以下匹配:

result_b <- data.table(
  group_id1=c(1,2,3,3),
  group_id2=c(1,1,1,2)
)
Run Code Online (Sandbox Code Playgroud)

我该如何实现a)或b)?优选地,以数据表格的方式.

EDIT1:添加了a)和b)的预期结果

EDIT2:向d_grouped添加了更多组,因此分组变量重叠.这打破了一些建议的解决方案

Uwe*_*Uwe 2

这个答案集中在问题的a)部分。

它遵循Harland 的方法,但出于性能原因尝试更好地利用该data.table习惯用法,因为 OP 提到他的生产数据可能包含数百万个观察结果。

样本数据

library(data.table)
d1 <- data.table(
  group_id1 = 1:4,
  Cat_grouped = list(letters[1:2], letters[3:2], letters[3:6], letters[11:12]))

d_grouped <- data.table(
  group_id2 = 1:2,
  Cat_grouped = list(letters[1:5], letters[6:10]))
Run Code Online (Sandbox Code Playgroud)

结果一)

grp_cols <- c("group_id1", "group_id2")
unique(d1[, .(unlist(Cat_grouped), lengths(Cat_grouped)), by = group_id1][
  d_grouped[, unlist(Cat_grouped), by = group_id2], on = "V1", nomatch = 0L][
    , .(V2, .N), by = grp_cols][V2 == N, ..grp_cols])

   group_id1 group_id2
1:         1         1
2:         2         1
Run Code Online (Sandbox Code Playgroud)

解释

d1将和的列表元素扩展为长格式时,使用该函数d_grouped确定列表元素的数量。(注意与 的区别)获取列表中每个元素的长度,并在 R 3.2.0 中引入。d1lengths()lengths()length()

内连接(注意参数)之后,将针对 的每个组合nomatch = 0L计算结果集中的行数(使用特殊符号) 。仅考虑结果集中的计数与列表的原始长度匹配的那些行。最后,返回的唯一组合。.Ngrp_colsgrp_cols

结果 b)

结果 b) 可以通过省略计数内容从上述解决方案中导出:

unique(d1[, unlist(Cat_grouped), by = group_id1][
  d_grouped[, unlist(Cat_grouped), by = group_id2], on = "V1", nomatch = 0L][
      , c("group_id1", "group_id2")])
Run Code Online (Sandbox Code Playgroud)
   group_id1 group_id2
1:         1         1
2:         2         1
3:         3         1
4:         3         2
Run Code Online (Sandbox Code Playgroud)