这类似于Update values in data.table with values from another data.table和R data.table replacing an index of values from another data.table,除了在我的情况下变量的数量非常大,所以我不想明确列出它们。
我拥有的是一个较大的data.table
(我们称之为dt_original
)和一个较小的data.table
(我们称之为dt_newdata
),其ID是第一个的子集它只有第一个变量。我想使用dt_original
中的值更新dt_newdata
中的值。另外,我 希望有条件地更新值 - 在这种情况下,仅当dt_newdata
中的值大于dt_original
中的相应值时才。
对于可重现的示例,以下是数据。在现实世界中,表格要大得多:
library(data.table)
set.seed(0)
## This data.table with 20 rows and many variables is the existing data set
dt_original <- data.table(id = 1:20)
setkey(dt_original, id)
for(i in 2015:2017) {
varA <- paste0('varA_', i)
varB <- paste0('varB_', i)
varC <- paste0('varC_', i)
dt_original[, (varA) := rnorm(20)]
dt_original[, (varB) := rnorm(20)]
dt_original[, (varC) := rnorm(20)]
}
## This table with a strict subset of IDs from dt_original and only a part of
## the variables is our potential replacement data
dt_newdata <- data.table(id = sample(1:20, 3))
setkey(dt_newdata, id)
newdata_vars <- sample(names(dt_original)[-1], 4)
for(var in newdata_vars) {
dt_newdata[, (var) := rnorm(3)]
}
以下是使用循环和pmax
进行此操作的方法,但必须有更好的方法,对吗?
for(var in newdata_vars) {
k <- pmax(dt_newdata[, (var), with = FALSE], dt_original[id %in% dt_newdata$id, (var), with = FALSE])
dt_original[id %in% dt_newdata$id, (var) := k, with = FALSE]
}
似乎应该有一种方法可以使用连接语法,可能是前缀i.
和/或.SD
或类似的东西,但我尝试过的任何内容都不足以保证在此重复
答案 0 :(得分:4)
根据您的标准,此代码应以当前格式运行。
app_name
它连接到data.tables之间匹配的ID,然后使用dt_original[dt_newdata, names(dt_newdata) := Map(pmax, mget(names(dt_newdata)), dt_newdata)]
执行分配因为我们想要返回一个列表,所以我使用:=
来运行Map
data.tables的列,由dt_newdata的名称匹配。请注意,dt_newdata的所有名称都必须位于dt_original数据中。
根据Frank的评论,您可以使用pmax
删除Map
列表项的第一列和列名,因为它们是ID,不需要计算。从[-1]
中删除第一列可以避免Map
的一次传递,并且还会保留ID上的密钥。感谢@ brian-stamper指出评论中的密钥保存。
pmax
请注意,dt_original[dt_newdata,
names(dt_newdata)[-1] := Map(pmax,
mget(names(dt_newdata)[-1]),
dt_newdata[, .SD, .SDcols=-1])]
的使用假定ID变量位于new_data的第一个位置。如果它在其他地方,您可以手动更改索引或使用[-1]
。