4

我想做与此处解释的相同的操作,即将缺失的行添加到 data.table。我面临的唯一额外困难是我希望关键列的数量,即用于自连接的那些行,是灵活的。

这是一个小例子,基本上重复了上面提到的链接中所做的事情:

df <- data.frame(fundID   = rep(letters[1:4], each=6),
                 cfType   = rep(c("D", "D", "T", "T", "R", "R"), times=4),
                 variable = rep(c(1,3), times=12),
                 value    = 1:24)
DT <- as.data.table(df)
idCols <- c("fundID", "cfType")
setkeyv(DT, c(idCols, "variable"))
DT[CJ(unique(df$fundID), unique(df$cfType), seq(from=min(variable), to=max(variable))), nomatch=NA]

困扰我的是最后一行。我想要idCols灵活(例如,如果我在函数中使用它),所以我不想unique(df$fundID), unique(df$cfType)手动输入。但是,我只是没有找到任何解决方法。我所有尝试根据df需要CJ自动将作为键列类型。

CJ(sapply(df[, idCols], unique))
CJ(unique(df[, idCols]))
CJ(as.vector(unique(df[, idCols])))
CJ(unique(DT[, idCols, with=FALSE]))

我也尝试自己构建表达式:

str <- ""
for (i in idCols) {
  str <- paste0(str, "unique(df$", i, "), ")
}
str <- paste0(str, "seq(from=min(variable), to=max(variable))")
str
[1] "unique(df$fundID), unique(df$cfType), seq(from=min(variable), to=max(variable))"

但是后来我不知道如何使用str. 这一切都失败了:

CJ(eval(str))
CJ(substitute(str))
CJ(call(str))

有谁知道一个好的解决方法?

4

2 回答 2

4

迈克尔的回答很棒。do.call确实需要以CJ这种方式灵活调用,afaik。

要清除表达式构建方法并从您的代码开始,但删除df$部分(不需要并且在链接答案中未完成,因为i在 范围内评估DT):

str <- "" 
for (i in idCols) { 
  str <- paste0(str, "unique(", i, "), ") 
} 
str <- paste0(str, "seq(from=min(variable), to=max(variable))") 
str 
[1] "unique(fundID), unique(cfType), seq(from=min(variable), to=max(variable))" 

然后是:

expr <- parse(text=paste0("CJ(",str,")"))
DT[eval(expr),nomatch=NA]

或者动态地构建和评估整个查询:

eval(parse(text=paste0("DT[CJ(",str,"),nomatch=NA")))

如果这样做很多,那么可能值得为自己创建一个辅助函数:

E = function(...) eval(parse(text=paste0(...)))

减少到:

E("DT[CJ(",str,"),nomatch=NA")
于 2012-08-08T15:11:19.300 回答
3

我从来没有使用过 data.table 包,所以如果我错过了这里的标记,请原谅我,但我想我已经明白了。这里发生了很多事情。从阅读开始do.call,它允许您以一种非传统方式评估任何函数,其中参数由提供的列表指定(列表中的每个元素在位置上与函数参数匹配,除非明确命名)。另请注意,我必须指定min(df$variable)而不仅仅是min(variable). 阅读Hadley 的关于范围界定的页面,以了解这里的问题。

CJargs <- lapply(df[, idCols], unique)
names(CJargs) <- NULL
CJargs[[length(CJargs) +1]] <- seq(from=min(df$variable), to=max(df$variable))
DT[do.call("CJ", CJargs),nomatch=NA]
于 2012-07-26T22:18:12.910 回答