R data.table有条件地使用另一个data.table中的值替换数据

R data.table有条件地使用另一个data.table中的值替换数据,r,data.table,R,Data.table,这与和类似,只是在我的情况下,变量的数量非常大,所以我不想显式地列出它们 我拥有的是一个大的数据表(我们称之为dt_original)和一个较小的数据表(我们称之为dt_newdata),它的ID是第一个的子集,并且只有第一个的一些变量。我想用dt\u newdata中的值更新dt\u original中的值。对于附加的扭曲,我只想有条件地更新值-在本例中,仅当dt_newdata中的值大于dt_original中的相应值时 对于可再现的示例,以下是数据。在现实世界中,表格要大得多: libra

这与和类似,只是在我的情况下,变量的数量非常大,所以我不想显式地列出它们

我拥有的是一个大的
数据表
(我们称之为
dt_original
)和一个较小的
数据表
(我们称之为
dt_newdata
),它的ID是第一个的子集,并且只有第一个的一些变量。我想用
dt\u newdata
中的值更新
dt\u original
中的值。对于附加的扭曲,我只想有条件地更新值-在本例中,仅当
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)]
}

似乎应该有一种使用连接语法的方法,可能还有前缀
i.
和/或
.SD
或类似的东西,但是我尝试过的任何东西都不足以保证在这里重复。

根据您的标准,此代码应该以当前格式工作

dt_original[dt_newdata, names(dt_newdata) := Map(pmax, mget(names(dt_newdata)), dt_newdata)]
它连接到data.tables之间匹配的ID,然后使用
:=
执行赋值,因为我们想要返回一个列表,所以我使用
Map
通过data.tables的列运行
pmax
,这些列通过dt_newdata的名称匹配。请注意,所有dt_newdata的名称都必须在dt_原始数据中

在Frank的评论之后,您可以使用
[-1]
删除
映射
列表项的第一列和列名,因为它们是不需要计算的ID。从
Map
中删除第一列可以避免一次通过
pmax
,还可以保留id上的密钥。感谢@brian stamper在注释中指出密钥保留

dt_original[dt_newdata,
            names(dt_newdata)[-1] := Map(pmax,
                                         mget(names(dt_newdata)[-1]),
                                         dt_newdata[, .SD, .SDcols=-1])]

请注意,
[-1]
的使用假定ID变量位于新数据的第一个位置。如果在别处,您可以手动更改索引或使用
grep

根据您的条件,此代码应以当前格式工作

dt_original[dt_newdata, names(dt_newdata) := Map(pmax, mget(names(dt_newdata)), dt_newdata)]
它连接到data.tables之间匹配的ID,然后使用
:=
执行赋值,因为我们想要返回一个列表,所以我使用
Map
通过data.tables的列运行
pmax
,这些列通过dt_newdata的名称匹配。请注意,所有dt_newdata的名称都必须在dt_原始数据中

在Frank的评论之后,您可以使用
[-1]
删除
映射
列表项的第一列和列名,因为它们是不需要计算的ID。从
Map
中删除第一列可以避免一次通过
pmax
,还可以保留id上的密钥。感谢@brian stamper在注释中指出密钥保留

dt_original[dt_newdata,
            names(dt_newdata)[-1] := Map(pmax,
                                         mget(names(dt_newdata)[-1]),
                                         dt_newdata[, .SD, .SDcols=-1])]

请注意,
[-1]
的使用假定ID变量位于新数据的第一个位置。如果在别处,您可以手动更改索引或使用
grep

是的,您的pmax看起来非常像
dt_original[dt_newdata,on=(id),pmax(x.varB,i.varB)]
,唯一的问题是坚持将“varB”作为字符传递。。。可能可以通过将数据放在长格式而不是宽格式中来解决。请使用
set.seed
使此文件重新生成
set.seed(0)
,谢谢。将
varB
视为几百个变量名的混合体,是
dt\u original
中变量的任意子集。这个例子可能会让它看起来有点太常规了。名称是否异构并不重要。它们显然都是数字的(通过使用pmax来判断),这意味着它们在长格式数据集中的一列中可以很好地协同工作。这就是熔化(dt_original,id=“id”)。从这里开始,您可能还希望将var名称拆分为组件部分…(变量和年份)。如果你对此感兴趣,我建议你看看哈德利关于它的文章:是的,你的pmax看起来很像
dtu-original[dtu-newdata,on=(id),pmax(x.varB,I.varB)]
,唯一的问题是坚持将“varB”作为字符传递。。。可能可以通过将数据放在长格式而不是宽格式中来解决。请使用
set.seed
使此文件重新生成
set.seed(0)
,谢谢。将
varB
视为几百个变量名的混合体,是
dt\u original
中变量的任意子集。这个例子可能会让它看起来有点太常规了。名称是否异构并不重要。它们显然都是数字的(通过使用pmax来判断),这意味着它们在长格式数据集中的一列中可以很好地协同工作。这就是熔化(dt_original,id=“id”)。从这里开始,您可能还希望将var名称拆分为组件部分…(变量和年份)。如果你对此感兴趣,我建议你看看哈德利的文章:是的,看起来不错。不知道你是否希望它出现在所有栏目中;可能需要排除
id
。我想您可能在编辑之前就已经有了它-我正在尝试两种方法,并且使用
[-1]
它看起来像
pmax
正在尝试将
dt_original
的所有行与
dt_newdata
进行比较。好的。我返回了原始代码,然后添加了忽略id列的工作代码。有趣的旁注-如果您不跳过ID列,这将消除它是一个键的事实,因此您必须在结果上再次
setkey
(如果您想要键控数据)。
[-1]
版本保留了密钥。是的,看起来不错。不知道你是否希望它出现在所有栏目中;可能需要排除
id
。我想您可能在