从较小的 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))]
我正在寻找一种方法来填充来自计算的较小 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))]