用 data.table 在 R 中重建索引?

Reindexing in R with data.table?

这是我最近在 R 中遇到的一个常见问题 data.table

我有一个索引 table,比如 DT1。列 x 将是索引的子集。我将使用这些索引处理更大的 rawtable 的 subtable。 subtable 通常会从 1 到 N 进行索引。(即 y 列)

然后例如,我会遇到一个 table 与原始索引成对的索引,我想知道相应的新索引。

这是它的样子

DT1 <- data.table(x=c(0,3,5),y= c(11,22,33))
DT2 <- data.table(x=c(3,3,0,0,5),x=c(0,5,0,3,5))
# > DT1
#    x y
# 1: 0 11
# 2: 3 22
# 3: 5 33

# > DT2
#    x x
# 1: 3 0
# 2: 3 5
# 3: 0 0
# 4: 0 3
# 5: 5 5

这是我找到的一个曲折的方法

cbind(DT1[DT2[,1,with=FALSE],on="x"][,2,with=FALSE],DT1[DT2[,2,with=FALSE],on="x"][,2,with=FALSE])
#     y  y
# 1: 22 11
# 2: 22 33
# 3: 11 11
# 4: 11 22
# 5: 33 33

使用 sapply 执行此操作的更基本方法给出相同的结果

tab=DT1$x
lookup <- function(value){DT1$y[which(tab==value)]}

colnames(DT2) <- c("x","xx")

ans <- as.data.table(cbind(sapply(DT2$x,lookup),sapply(DT2$xx,lookup)))
colnames(ans) <- c("y","y")

然而, 第一个解决方案对我来说有点难看

我不喜欢第二个,因为我需要在每次使用 lapply 中的函数查找时定义一个值给选项卡。 如果我必须在不同的 table 中查找,我可以选择创建一个特定于 table 的新查找函数,或者将其存储在内存中的(临时)变量选项卡中。 也许有一种方法可以用两个变量的函数来做 lapply lookup <-function (tab,value) {...} ?我不知道

我相信还有很多其他方法。 我不确定第一个解决方案到底在做什么。基本上 data.table 中的语法与(内部和外部)JOINS 有关。但在最终输出中,我想保留 table DT2 的原始顺序。将列 x 设置为 DT2 的键将对该列进行排序,使 merge 之类的内容不适应该列?

我很乐意听取您的意见,什么是最好的实现,我相信还有很多更好的实现,而且,在处理非常非常大的 table 时效率最高。

您可以尝试以下操作:

DT2[, lapply(.SD, function(x) DT1[["y"]][match(x, DT1[["x"]])])]
#     x  x
# 1: 22 11
# 2: 22 33
# 3: 11 11
# 4: 11 22
# 5: 33 33
str(.Last.value)
# Classes ‘data.table’ and 'data.frame':    5 obs. of  2 variables:
#  $ x: num  22 22 11 11 33
#  $ x: num  11 33 11 22 33
#  - attr(*, ".internal.selfref")=<externalptr> 

惯用的 data.table 方法是 更新 DT2加入如下:

require(data.table) # v1.9.6
setnames(DT2, c("a", "b")) # no duplicate names!!
for (nm in names(DT2)) {
    DT2[DT1, paste0(nm, ".val") := y, on = structure("x", names=nm)]
}
DT2[]
#    a b a.val b.val
# 1: 3 0    22    11
# 2: 3 5    22    33
# 3: 0 0    11    11
# 4: 0 3    11    22
# 5: 5 5    33    33

也许您可以使用 lapply() 隐藏循环。如果 DT2 改为如下(长格式;参见 DT3):

DT3 = melt(DT2, measure = c("a", "b"), variable.name = "id", value.name = "x.val")

那么你可以这样做:

DT3[DT1, y.val := y, on = c(x.val = "x")] 

您可以使用 y.val := i.y 更明确地表示您指的是 data.table 中对应于 i 参数的 y 列..(当它们都有共同的列名)。