2017-03-31 58 views
0

我试图在data.table中执行滚动连接,它会引入多个列,但会遍历整个缺失的行,并且会在特定的列中滚动,即使该行存在。举例来说,我有两个表,A,并BRolling加入多个列以独立排除NAs

library(data.table) 
A <- data.table(v1 = c(1,1,1,1,1,2,2,2,2,3,3,3,3), 
       v2 = c(6,6,6,4,4,6,4,4,4,6,4,4,4), 
       t = c(10,20,30,60,60,10,40,50,60,20,40,50,60), 
       key = c("v1", "v2", "t")) 

B <- data.table(v1 = c(1,1,1,1,2,2,2,2,3,3,3,3), 
       v2 = c(4,4,6,6,4,4,6,6,4,4,6,6), 
       t = c(10,70,20,70,10,70,20,70,10,70,20,70), 
       valA = c('a','a',NA,'a',NA,'a','b','a', 'b','b',NA,'b'), 
       valB = c(NA,'q','q','q','p','p',NA,'p',NA,'q',NA,'q'), 
       key = c("v1", "v2", "t")) 

B 
##  v1 v2 t valA valB 
## 1: 1 4 10 a NA 
## 2: 1 4 70 a q 
## 3: 1 6 20 NA q 
## 4: 1 6 70 a q 
## 5: 2 4 10 NA p 
## 6: 2 4 70 a p 
## 7: 2 6 20 b NA 
## 8: 2 6 70 a p 
## 9: 3 4 10 b NA 
## 10: 3 4 70 b q 
## 11: 3 6 20 NA NA 
## 12: 3 6 70 b q 

如果我不滚动连接(在这种情况下,反向连接),它翻转所有的点当行不能被发现B,但仍包括点时存在行,但要合并的数据NA

B[A, , roll=-Inf] 

##  v1 v2 t valA valB 
## 1: 1 4 60 a q 
## 2: 1 4 60 a q 
## 3: 1 6 10 NA q 
## 4: 1 6 20 NA q 
## 5: 1 6 30 a q 
## 6: 2 4 40 a p 
## 7: 2 4 50 a p 
## 8: 2 4 60 a p 
## 9: 2 6 10 b NA 
## 10: 3 4 40 b q 
## 11: 3 4 50 b q 
## 12: 3 4 60 b q 
## 13: 3 6 20 NA NA 

我想以这样的方式来滚动加入它滚过这些NA S以及。对于单个列中,我可以子集B以除去NA s,则与A滚:

C <- B[!is.na(valA), .(v1, v2, t, valA)][A, roll=-Inf] 

C 
##  v1 v2 t valA 
## 1: 1 4 60 a 
## 2: 1 4 60 a 
## 3: 1 6 10 a 
## 4: 1 6 20 a 
## 5: 1 6 30 a 
## 6: 2 4 40 a 
## 7: 2 4 50 a 
## 8: 2 4 60 a 
## 9: 2 6 10 b 
## 10: 3 4 40 b 
## 11: 3 4 50 b 
## 12: 3 4 60 b 
## 13: 3 6 20 b 

但对多列,我必须这样做顺序,存储该值对于每个添加的列,然后重复。

B[!is.na(valB), .(v1, v2, t, valB)][C, roll=-Inf] 

##  v1 v2 t valB valA 
## 1: 1 4 60 q a 
## 2: 1 4 60 q a 
## 3: 1 6 10 q a 
## 4: 1 6 20 q a 
## 5: 1 6 30 q a 
## 6: 2 4 40 p a 
## 7: 2 4 50 p a 
## 8: 2 4 60 p a 
## 9: 2 6 10 p b 
## 10: 3 4 40 q b 
## 11: 3 4 50 q b 
## 12: 3 4 60 q b 
## 13: 3 6 20 q b 

上述最终结果是所期望的输出,但对于多个列它很快变得难以处理。有更好的解决方案吗?

回答

2

加入即将匹配了行。如果您想以多种方式匹配行,则需要多个连接。

我会使用一个循环,但添加列A(而不是创建新表C,d,......每个以下连接):

k  = key(A) 
bcols = setdiff(names(B), k) 

for (col in bcols) A[, (col) := 
    B[!.(as(NA, typeof(B[[col]]))), on=col][.SD, roll=-Inf, ..col] 
][] 

A 

    v1 v2 t valA valB 
1: 1 4 60 a q 
2: 1 4 60 a q 
3: 1 6 10 a q 
4: 1 6 20 a q 
5: 1 6 30 a q 
6: 2 4 40 a p 
7: 2 4 50 a p 
8: 2 4 60 a p 
9: 2 6 10 b p 
10: 3 4 40 b q 
11: 3 4 50 b q 
12: 3 4 60 b q 
13: 3 6 20 b q 

B[!.(NA_character_), on="valA"]是一种抗加入该行下降新手在valA。上面的代码试图概括这个(因为NA需要匹配列的类型)。

+0

这很好用!我没有立即去循环,因为我有时会发现,如果你在R中使用循环和数据结构,你经常做错了。但有时候我猜是不可避免的。 –

+0

为了让我明白发生了什么,你在'!is.na(col)'上对'B'进行了子集化,并且进行自卷联接以滚动该列的数据,是吗? '..col'是对'on ='的隐式调用吗? –

+1

是的,反连接和!is.na一样。下一个连接本质上是'A [,v:= B [A,v]]',除了我们可以使用'.SD'而不是第二次写'A';所以它不是一个真正的自我加入。 '.v'符号用于选择存储在变量中的列(不使用'on =';键仍然在这里确定连接)。 – Frank