我有一些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
基于a
和b
创建一个新列,它是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
中的列时,它不会被存储(这是有意义的,因为它看起来我正在尝试将新列保存到{{ 1}})。
x[y]
有没有办法执行上述操作但将输出保存到x[y][, val:=sapply(1:nrow(x), function (i) a[i] + b[i])]
?
这是我应该怎么做的,还是有更多的x[, val]
- y方式?
data.table
答案 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