滚动独立连接多个列以消除NA

时间:2017-03-31 21:02:50

标签: r join data.table

我正在尝试在data.table中进行滚动连接,这会引入多个列,但会滚动整个缺失的行,并在特定列中滚动单个NA,即使该行存在也是如此。举例来说,我有两个表,AB

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。对于单个列,我可以将B分组以删除NA,然后使用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

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

1 个答案:

答案 0 :(得分: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中删除带有NAs的行。上面的代码试图概括这一点(因为NA需要匹配列的类型)。