data.table 非加入一列

data.table non-join on one column

我正在尝试在 data.table 中进行连接,其中一组列与另一个匹配 table 我想要第三列中的所有值 table 不'存在于初始table。这是一个例子:

library(foreach)
library(data.table)

tmp <- data.table(mgr=c('1','1','1','1',
                        '2','2',
                        '3','3'),
                  year=rep(2022,8),
                  stocks=c('A','B','C','D',
                           'A','B',
                           'C','D'))

输入 table 如下所示:

   mgr year stocks
1:   1 2022      A
2:   1 2022      B
3:   1 2022      C
4:   1 2022      D
5:   2 2022      A
6:   2 2022      B
7:   3 2022      C
8:   3 2022      D

然后我得到所有独特的股票-年份组合。然后对于每个 mgr-year 我想要不在 tmp 中的股票对于特定的 mgr-year 对:

allstocks <- unique(tmp[,.(year,stocks)])

myloop <- unique(tmp[,.(mgr,year)])

out <- foreach(myidx=1:nrow(myloop)) %do% {
    tmp1 <- tmp[myloop[myidx],on=.NATURAL]
    tmp1 <- allstocks[!tmp1,on=.(year,stocks)]
    tmp1 <- merge(myloop[myidx],tmp1,by=c('year'))
    tmp1
}

finalout <- rbindlist(out)

finalout

这给出:

   year mgr stocks
1: 2022   2      C
2: 2022   2      D
3: 2022   3      A
4: 2022   3      B

由于经理 1 拥有所有库存,因此没有该经理的行。我也同意在特定经理年的股票中与 NA 发生争执。

实际上我想要的是为每个股票年获得每个经理不持有的股票清单。这个例子有效,但实际数据是 ~100mm 行所以我想知道是否有一种方法可以有效地使用纯 data.table 来做到这一点。

谢谢。

data.table 中有一个 ! 运算符用于排除。

setkey(tmp, mgr, year, stocks)
all.stocks <- tmp[, .(stocks=unique(tmp$stocks)), by=.(mgr, year)]
setkey(all.stocks, mgr, year, stocks)
missing <- all.stocks[!tmp]

这应该很快。

为了完整起见,这里有一个使用

的“one-liner”
  • cross join CJ() 以创建 mgryearstocks、[= 的所有唯一可能组合37=]
  • 排他性连接运算符!,
  • on = 子句指示要加入的列,
  • data.table 链接:
tmp[, CJ(mgr, year, stocks, unique = TRUE)][!tmp, on  = .(mgr, year, stocks)]
Key: <mgr, year, stocks>
      mgr  year stocks
   <char> <num> <char>
1:      2  2022      C
2:      2  2022      D
3:      3  2022      A
4:      3  2022      B

请注意,不需要 显式调用 setkey(),因为 CJ() 的默认参数 sorted = TRUE 已经设置了密钥并且 on 使用这些。