gpt4 book ai didi

r - 在 data.table 和/或 dplyr 中跨组和列应用函数

转载 作者:行者123 更新时间:2023-12-04 15:03:13 25 4
gpt4 key购买 nike

我想合并两个不等行的数据表或数据帧,其中 dt2 的行数与 dt1 的组数相同。这是一个可重现的例子:

a <- 1:10; b <- 2:11; c <- 3:12
groupVar <- c(1,1,1,2,2,2,3,3,3,3)
dt1 <- data.table(a,b,c,groupVar)
a2 <- c(10,20,30); b2 <- c(20,30,40); c2 <- c(30,40,50)
dt2 <- data.table(a2,b2,c2)

实际情况涉及大量列,因此我需要使用变量来引用它们。使用循环或应用,我希望将 dt2 的每一行添加到包含每组 dt1 的行中。这是许多失败的尝试之一:

for (ic in 1:3) {
c1 <- dt2[,(ic), with=FALSE]
c2 <- dt2[,(ic), with=FALSE]
dt1[,(ic) := .(c1 + c2[.G]), by = "groupVar"]
}

我对如何在 data.table 语法和 dplyr 语法中“按组和按列”进行这种操作很感兴趣。到位(如上所述)并不重要。

期望的结果:

dt1 (or dt3) = 
a b c groupVar
11 22 33 1
12 23 34 1
13 24 35 1
24 35 46 2
...
40 51 62 3

最佳答案

随问题提供的示例数据集表明列的名称可能因数据集而异,例如,应该添加 b 的列 dt1b2 的列 dt2

这里有两种方法应该适用于任意数量的任意命名的列对:

  1. 以长格式工作
  2. 编辑:使用 get() 更新连接
  3. 编辑 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 为长格式。

# 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." by vars2[iv]"i." by := 的变量名是为了确保在列名重复的情况下从 dt1dt2 中选择正确的列。请参阅关于 jhelp("data.table") 参数的高级部分。

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), `:=`(", ., ")][]")}

请注意,点 . 和花括号 {} 在不同的上下文中具有不同的含义,这可能看起来有些困惑。

关于r - 在 data.table 和/或 dplyr 中跨组和列应用函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66616164/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com