2

我有一些data.tables这样的:

x <- data.table(id=rep(1:3, 2), a=1:6)
y <- data.table(id=1:3, b=2:4)

我可以像这样合并它们:

setkey(x, id)
setkey(y, id)
x[y]
   id a b
1:  1 1 2
2:  1 4 2
3:  2 2 3
4:  2 5 3
5:  3 3 4
6:  3 6 4

现在,我想在x基础上创建一个新列ab它是和的a总和b。我可以这样做:

x[y, val:=a + b]

但是,现在假设由于某种原因“+”运算符未矢量化。如何将逐行计算存储到计算所需的x位置?x[y]另外,假设我不能使用mapply(因为我的实际问题,mapply不适合该功能)。

我正在尝试sapply像这样以逐行方式添加:

x[y, sapply(1:nrow(x), function (i) a[i] + b[i])]

但是,这会返回错误的结果:

    id V1
 1:  1  3
 2:  1 NA
 3:  1 NA
 4:  1 NA
 5:  1 NA
 6:  1 NA
 7:  2  5
 8:  2 NA
 9:  2 NA
10:  2 NA
11:  2 NA
12:  2 NA
13:  3  7
14:  3 NA
15:  3 NA
16:  3 NA
17:  3 NA
18:  3 NA

如果我这样做,它会起作用:

x[y][, sapply(1:nrow(x), function (i) a[i] + b[i])]
# [1] 3 6 5 8 7 10

但是当我尝试将其分配给 中的列时x,它不会被存储(这很有意义,因为看起来我正在尝试将新列保存到 中x[y])。

x[y][, val:=sapply(1:nrow(x), function (i) a[i] + b[i])]

有什么办法可以做到以上,但将输出保存到x[, val]? 这是我应该这样做的方式,还是有更多的data.table方式?

x[, val:=x[y][, sapply(1:nrow(x), function (i) a[i] + b[i])]]
4

1 回答 1

5

你是在by-without-by不知不觉中做的,(请参阅下面的帮助描述)

高级:在 i 中传递这些组时,已知组子集的聚合特别有效。当 i 是 data.table 时,DT[i,j] 为 i 的每一行计算 j。我们将其称为不使用 by 或按 i 分组。因此,自连接 DT[data.table(unique(colA)),j] 与 DT[,j,by=colA] 相同。

这意味着对( 一次循环j一行的每一行进行评估- 因此,如果您在其中运行,它将每次创建一个长度向量,而这不是您想要的。iysapply(1:nrow(x),...)jnrow(x)

所以你的第二个选择绝对是一种有效的方法(因为它是这样做的推荐方法之一)

否则,您可以使用.N当按 i 分组时,.N 是 x 中匹配的行数,对于 i 的每一行nrow(x),但您必须考虑对象的长度以及如何对函数进行矢量化.

以此为例

x[y, {browser(); a+b}]
Called from: `[.data.table`(x, y, {
    browser()
    a + b
})
Browse[1]> a
[1] 1 4
Browse[1]> b
[1] 2
Browse[1]> .N
[1] 2

a长度为 2,因为键的值与 x 中的 2 行匹配。b只有长度1,因为它只有长度 1 in y

我认为最好的方法是正确地矢量化你的函数(如果没有更多的例子很难给出建议)

另一种方法是复制ba例如

 x[y, val := {
 bl <- rep_len(b, .N)
 sapply(seq_len(.N), function(i) a[i] + bl[i])}]
x
   id a val
1:  1 1   3
2:  1 4   6
3:  2 2   5
4:  2 5   8
5:  3 3   7
6:  3 6  10

或者,如果您知道y的每个值都有唯一的行id,那么您不需要尝试从中索引任何列。

x[y, val2 := sapply(seq_len(.N), function(i) a[i] + b)]
# an alternative would be to use sapply on a (avoid creating another vector)
x[y, val3 := sapply(a, function(ai) ai + b)]
x
#    id a val val2 val3
# 1:  1 1   3    3    3
# 2:  1 4   6    6    6
# 3:  2 2   5    5    5
# 4:  2 5   8    8    8
# 5:  3 3   7    7    7
# 6:  3 6  10   10   10
于 2013-04-30T04:25:39.040 回答