问题提供的示例数据集表明,数据集之间的列名称可能不同,例如,dt1 的列 b 和 dt2 的列 b2 应该被添加。
以下两种方法应该适用于任意数量的任意命名的列对:
- 以长格式工作
-
编辑: 使用
get() 更新联接
-
编辑 2: 计算语言
1。以长格式工作
可以在查找表或翻译表中提供对应列的信息:
library(data.table)
lut <- data.table(vars1 = c("a", "b", "c"), vars2 = c("a2", "b2", "c2"))
lut
vars1 vars2
1: a a2
2: b b2
3: c c2
如果列名被视为数据并且列数据属于相同的数据类型,我的第一种方法是重塑为长格式。
# reshape to long format
mdt1 <- melt(dt1[, rn := .I], measure.vars = lut$vars1)
mdt2 <- melt(dt2[, groupVar := .I], measure.vars = lut$vars2)
# update join to translate variable names
mdt2[lut, on = .(variable = vars2), variable := vars1]
# update join to add corresponding values of both tables
mdt1[mdt2, on = .(groupVar, variable), value := x.value + i.value]
# reshape backe to wide format
dt3 <- dcast(mdt1, rn + groupVar ~ ...)[, rn := NULL][]
dt3
groupVar a b c
1: 1 11 22 33
2: 1 12 23 34
3: 1 13 24 35
4: 2 24 35 46
5: 2 25 36 47
6: 2 26 37 48
7: 3 37 48 59
8: 3 38 49 60
9: 3 39 50 61
10: 3 40 51 62
2。使用get() 更新连接
再想一想,这是一种类似于 OP 提出的for 循环的方法,并且需要更少的编码:
vars1 <- c("a", "b", "c")
vars2 <- c("a2", "b2", "c2")
dt2[, groupVar := .I]
for (iv in seq_along(vars1)) {
dt1[dt2, on = .(groupVar),
(vars1[iv]) := get(paste0("x.", vars1[iv])) + get(paste0("i.", vars2[iv]))][]
}
dt1[]
a b c groupVar
1: 11 22 33 1
2: 12 23 34 1
3: 13 24 35 1
4: 24 35 46 2
5: 25 36 47 2
6: 26 37 48 2
7: 37 48 59 3
8: 38 49 60 3
9: 39 50 61 3
10: 40 51 62 3
请注意,dt1 是通过引用更新的,即不进行复制。
在:=的右侧将变量名vars1[iv]添加到"x."和vars2[iv]前添加"i."是为了确保来自dt1和dt2的右列分别,在列名重复的情况下选择。请参阅help("data.table") 中j 参数的高级: 部分。
3。语言计算
这在Matt Dowle's advice 之后创建一个要评估的表达式,“类似于构造动态 SQL 语句以发送到服务器”。有关另一个用例,请参阅 here。
library(glue) # literal string interpolation
library(magrittr) # piping used to improve readability
EVAL <- function(...) eval(parse(text = paste0(...)), envir = parent.frame(2))
data.table(vars1 = c("a", "b", "c"), vars2 = c("a2", "b2", "c2")) %>%
glue_data("{vars1} = x.{vars1} + i.{vars2}") %>%
glue_collapse( sep = ", ") %>%
{glue("dt1[dt2[, groupVar := .I], on = .(groupVar), `:=`({.})][]")} %>%
EVAL()
a b c groupVar
1: 11 22 33 1
2: 12 23 34 1
3: 13 24 35 1
4: 24 35 46 2
5: 25 36 47 2
6: 26 37 48 2
7: 37 48 59 3
8: 38 49 60 3
9: 39 50 61 3
10: 40 51 62 3
它以一个查找表开始,它是动态创建的,随后被操作以形成一个完整的data.table语句
dt1[dt2[, groupVar := .I], on = .(groupVar), `:=`(a = x.a + i.a2, b = x.b + i.b2, c = x.c + i.c2)][]
作为字符串。然后一次性评估和执行该字符串;不需要for 循环。
由于辅助函数EVAL() 已经使用paste0(),所以可以省略对glue() 的调用:
data.table(vars1 = c("a", "b", "c"), vars2 = c("a2", "b2", "c2")) %>%
glue_data("{vars1} = x.{vars1} + i.{vars2}") %>%
glue_collapse( sep = ", ") %>%
{EVAL("dt1[dt2[, groupVar := .I], on = .(groupVar), `:=`(", ., ")][]")}
请注意,点 . 和大括号 {} 在不同的上下文中具有不同的含义,这可能看起来有些混乱。