data.table在合并中使用`sapply`进行分配

时间:2013-04-30 04:06:59

标签: r data.table

我有一些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创建一个新列,它是ab的总和。 我可以这样做:

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中的列时,它不会被存储(这是有意义的,因为它看起来我正在尝试将新列保存到{{ 1}})。

x[y]

有没有办法执行上述操作但将输出保存到x[y][, val:=sapply(1:nrow(x), function (i) a[i] + b[i])] ? 这是我应该怎么做的,还是有更多的x[, val] - y方式?

data.table

1 个答案:

答案 0 :(得分:5)

您在不知情的情况下正在by-without-by,(请参阅下面的帮助说明)

  

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

这意味着j的每一行都会对i进行评估(每次排成y行 - 因此,如果您在{{{}}中运行sapply(1:nrow(x),...) 1}}每次都会创建一个长度为j的向量,这不是你想要的。

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

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

以此为例

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 长度为2,因为键的值与x的2行匹配。 a只有b长度,因为1的长度只有1。

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

另一种方法是将y复制到b的长度,例如

a

或者如果您知道 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