我正在尝试使用data.table,其中j
函数可以并且将在每次调用时返回不同数量的列。我希望它的行为类似于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)
任何想法都赞赏。
答案 0 :(得分:6)
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]
}
答案 1 :(得分: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']
使用by
来检查单个值似乎很浪费(可能是计算上的,但也就清晰度而言);当然,可能是你的应用程序不是那样的。
答案 2 :(得分:2)
尝试
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]