7

我正在尝试在我的j函数可以并且将在每次调用时返回不同数量的列的地方使用 data.table。我希望它表现得像rbind.fill它用NA.

fetch <- function(by) {
    if(by == 1)
        data.table(A=c("a"), B=c("b"))
    else
        data.table(B=c("b"))
}
data <- data.table(id=c(1,2))
result <- data[, fetch(.BY), by=id]

在这种情况下,“结果”可能会以两列结尾;A 和 B。 'A' 和 'B' 作为第一次调用 'fetch' 的一部分返回,只有 'B' 作为第二次调用的一部分返回。我希望示例代码返回此结果。

  id    A B
1  1    a b
2  2 <NA> b

不幸的是,运行时出现此错误。

Error in `[.data.table`(data, , fetch(.BY, .SD), by = id) : 
j doesn't evaluate to the same number of columns for each group

我可以这样做plyr,但在我的真实世界用例plyr中内存不足。每次调用都fetch发生得相当快,但是当plyr尝试将所有数据重新合并在一起时会发生内存崩溃。我想看看是否data.table可以为我解决这个问题。

result <- ddply(data, "id", fetch)

任何想法表示赞赏。

4

3 回答 3

7

DWin 的方法很好。或者您可以list改为返回一列,其中每个单元格本身就是一个向量。这通常是处理可变长度向量的更好方法。

DT = data.table(A=rep(1:3,1:3),B=1:6)
DT
   A B
1: 1 1
2: 2 2
3: 2 3
4: 3 4
5: 3 5
6: 3 6
ans = DT[, list(list(B)), by=A]
ans
   A    V1
1: 1     1
2: 2   2,3     # V1 is a list column. These aren't strings, the
3: 3 4,5,6     # vectors just display with commas

ans$V1[3]
[[1]]
[1] 4 5 6

ans$V1[[3]]
[1] 4 5 6

ans[,sapply(V1,length)]
[1] 1 2 3

因此,在您的示例中,您可以按如下方式使用它:

library(plyr)

rbind.fill(data[, list(list(fetch(.BY))), by = id]$V1)
#     A B
#1    a b
#2 <NA> b

或者,只需使返回的列表符合要求:

allcols = c("A","B")
fetch <- function(by) {
    if(by == 1)
        list(A=c("a"), B=c("b"))[allcols]
    else
        list(B=c("b"))[allcols]
}
于 2013-09-26T19:29:02.183 回答
4

这里有两种方法。第一个大致遵循您的策略:

data[,list(A=if(.BY==1) 'a' else NA_character_,B='b'), by=id]

第二个分两步做事:

DT <- copy(data)[,`:=`(A=NA_character_,B='b')][id==1,A:='a']

使用 a byjust 来检查单个值似乎很浪费(可能在计算上,但在清晰度方面);当然,也可能是您的应用程序并非如此。

于 2013-09-27T01:35:20.983 回答
3

尝试

            data.table(A=NA, B=c("b"))

@NickAllen:从评论中我不确定您是否理解我的建议。(我用手机发帖限制了我的剪切粘贴功能,我怀疑我的妻子告诉我不要再给 S0 发短信,否则她会和我离婚。)我的意思是:

fetch <- function(by) {
    if(by == 1)
        data.table(A=c("a"), B=c("b"))
    else
        data.table(A=NA, B=c("b"))
}
data <- data.table(id=c(1,2))
result <- data[, fetch(.BY), by=id]
于 2013-09-26T19:14:36.993 回答