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()
以创建 mgr
、year
和 stocks
、[= 的所有唯一可能组合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
使用这些。
我正在尝试在 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()
以创建mgr
、year
和stocks
、[= 的所有唯一可能组合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
使用这些。