从较小的 data.table 中填充 data.table

Filling a data.table from smaller data.tables

我正在寻找一种方法来填充来自计算的较小 data.table 的 Result data.table。 我的方法如下:

#CREATE EXAMPLE

library(data.table)

# The empty table to be filled

DT <- data.table(
   "ID" = c("a", "b", "c", "d"),
   "A" = numeric(4),
   "B" = numeric(4))

   ID A B
1:  a 0 0
2:  b 0 0
3:  c 0 0
4:  d 0 0

# Table with part of the results
DT_short <- data.table(
         "ID" = c("a", "b", "d"),
         "A" = 1:3,
         "B" = 1:3)

   ID A B
1:  a 1 1
2:  b 2 2
3:  d 3 3

我想做的是根据名称填充行和列。 我设法访问了大 data.table 我想更改的部分

nm1 <- names(DT_short)
DT[ID %in% DT_short[, ID], ..nm1]
#Bonus question: Why do I have to assign nm1 before, how do I make it work directly in []?

现在我想用小 table DT_short 替换 DT 的这一部分,但是我尝试过的所有方法(比如 <-:= ,或某种 merge) 无效。例如。 DT[ID %in% DT_short[, ID], ..nm1] <- DT_short

的错误 object '..nm1' not found

请帮助我提供解决方案或为我指明正确的方向。 (因为我正在处理的数据相当小——10^2 列,10^2 行,~40 个要组合的小文件,每个字段的数量<10^9——其他人会使用我的代码,可读性比表现。)

编辑

回应 Ronak Shah。当我使用下面的代码测试您的解决方案时,它在没有任何 errors/warnings 的情况下运行良好。在接受该解决方案之前,我想确保它也适用于其他人/知道为什么它会导致警告你而不是我。

library(data.table)
packageVersion('data.table')
#[1] ‘1.12.8’

#the empty table to be filled
DT <- data.table(
  "ID" = c("a", "b", "c", "d"),
  "A" = numeric(4),
  "B" = numeric(4),
  "C" = numeric(4)
)
#   ID A B C
#1:  a 0 0 0
#2:  b 0 0 0
#3:  c 0 0 0
#4:  d 0 0 0

#table with part of the results
DT_short <- data.table(
  "ID" = c("a", "b", "d"),
  "A" = 1:3,
  "B" = 1:3
)
#   ID A B
#1:  a 1 1
#2:  b 2 2
#3:  d 3 3

#table with part of the results 2
DT_shorter <- data.table(
  "ID" = c("c"),
  "A" = 7,
  "B" = 70,
  "C" = 3.14
)
#   ID A  B    C
#1:  c 7 70 3.14


DT[match(DT_short$ID, DT$ID), match(names(DT_short), names(DT))] <- DT_short
DT[match(DT_shorter$ID, DT$ID), match(names(DT_shorter), names(DT))] <- DT_shorter
DT
#   ID A  B    C
#1:  a 1  1 0.00
#2:  b 2  2 0.00
#3:  c 7 70 3.14
#4:  d 3  3 0.00

这是一种可能的方法。对于 mycols 中的每一列,您想要从 DT_short 中分配值。当您这样做时,您想要使用 match() 并获取索引,并使用它来创建一个新向量。创建新的 data.table 后,您希望将 NA 替换为 0.

library(data.table)

mycols <- names(DT)[2:3]

as.data.table(lapply(mycols, function(x){
    DT_short[match(x = DT$ID, table = DT_short$ID), ..x]}))[,
      (mycols) := replace(x = .SD, list = is.na(.SD), values = 0),
      .SDcols = mycols][]

#   A B
#1: 1 1
#2: 2 2
#3: 0 0
#4: 3 3

既然你提到你对其他解决方案没问题,这部分很容易用基础 R data.frames 完成,方法是从较大的数据帧中子集化较小的数据帧的行和列,并分配较短的数据帧。

df1 <- data.frame(DT)
df2 <- data.frame(DT_short)
df1[match(df2$ID, df1$ID), match(names(df2), names(df1))] <- df2

df1
#  ID A B
#1  a 1 1
#2  b 2 2
#3  c 0 0
#4  d 3 3

我认为对 data.table 做同样的事情是不对的,但是如果我们 运行 上面的代码就可以工作(至少对于共享的示例)

DT[match(DT_short$ID, DT$ID), match(names(DT_short), names(DT))] <- DT_short

但它 returns 一个很大的警告消息,它确认这不是 data.tables 的正确方法。

另一种选择是使用更新连接:

cols <- setdiff(names(DT_short), "ID")
DT[DT_short, on=.(ID), (cols) := mget(paste0("i.", cols))]