data.table使用来自另一个data.table的值替换数据,有条件地

时间:2017-03-01 16:52:28

标签: r data.table

这类似于Update values in data.table with values from another data.tableR 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或类似的东西,但我尝试过的任何内容都不足以保证在此重复

1 个答案:

答案 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]