使用join将值匹配到多个键列

时间:2013-11-06 14:22:57

标签: r join data.table

遵循这个线程(merge data.table when the number of key columns are different)的精神,我如何将表A中的键列与单个值(来自表或非表)匹配,其中A中的匹配行是至少一列时在A等于那个值?

这是一个简短的例子:假设我有表A:

A <- data.table(b1 = c(0, 1, 1, 1, 1), b2 = c(1, 1, 1, 1, 0), b3 = c(1, 0, 1, 1, 0), mis = FALSE)
setkey(A, b1, b2, b3)

假设我想在A的至少一列中匹配的值是0.所以A中的匹配行将是行1,2和5.我可以使用这个得到这个结果:

A[b1 == 0 | b2 == 0 | b3 == 0, ] # this is not so fast if A is large

    b1 b2 b3
1:  0  1  1
2:  1  1  0
3:  1  0  0

是否可以获得相同的结果,但使用更快的连接或合并操作?

我尝试了一些事情,例如:

B <- data.table(v = 0)
A[B, ] # only matches with column b1 in A

或者这个:

B <- data.table[b1 = 0, b2 = 0, b2 = 0]
setkey(B, b1, b2, b3)
A[B, ] # matches when all three corresponding columns match

是否有可能提出一种能够利用二分搜索速度来实现我正在寻找的结果的公式?

非常感谢你的帮助!

2 个答案:

答案 0 :(得分:1)

获得一点改进的一个简单技巧是使用连接进行第一次比较:

A[J(0), mis := TRUE]
A[b2 == 0 | b3 == 0, mis := TRUE]

请注意,虽然简单的比较总是比setkey +加入快 - 所以如果你每setkey多次这样做,或者如果密钥已经因其他原因而设置。


稍微思考一下 - 你可以通过减少所涉及的操作次数(到3而不是原来的5)来显着加快速度。下面的工作有点令人惊讶,因为它取代了大概更昂贵的操作(至少天真地我希望乘法更加昂贵),但它 快约2倍:

A[b1 * b2 * b3 == 0, mis := TRUE]

答案 1 :(得分:0)

我认为你的例子是一个普遍的例子而不是你正在处理的实际问题,所以我对数据采取了一些自由 -

library(data.table)
A <- data.table(
b1 = c(0, 1, 1, 1, 2), 
b2 = c(1, 2, 1, 1, 0), 
b3 = c(3, 0, 1, 1, 0)
)

Azerolist <- vector(mode = "list",length = ncol(A))

B1 <- data.table(
b11 = 0
)
setkeyv(A,c("b1"))
setkeyv(B1,c("b11"))
Azerolist[[1]] <- A[B1]
# b1 is zero, b2 or b3 might or might not be

B2 <- data.table(
b21 = 0,
b11 = 1
)
setkeyv(A,c("b2","b1"))
setkeyv(B2,c("b21","b11"))
Azerolist[[2]] <- A[B1, roll = Inf]
# b1 is not zero, b2 is zero, b3 might or might not be

B3 <- data.table(
b31 = 0,
b01 = 1
)
setkeyv(A,c("b3","b2"))
setkeyv(B3,c("b31","b01"))
A2 <- A[B1, roll = Inf]
setkeyv(A2,c("b3","b1"))
Azerolist[[3]] <- A2[B3, roll = Inf]
# b1 is not zero, b2 is not zero, b3 is zero

#ordering the columns in the same order for all data.tables in the list
Azerolist <- lapply(Azerolist, function(x) x[,colnames(A), with = FALSE])
# tada!
Azerodt <- rbindlist(Azerolist)