我想做与解释here相同的操作,即向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)
。但是,我没有找到任何解决方法。根据{{1}}的需要,我尝试自动将df
的子集拆分为向量的尝试失败,错误消息 setkeyv中的错误(x,cols,verbose = verbose):列'V1 '是类型'列表',它不是(当前)允许作为键列类型。
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
有没有人知道一个好的解决方法?
答案 0 :(得分:4)
do.call
以这种方式灵活地呼叫CJ
,afaik。
要了解表达式构建方法并从代码开始,但删除df$
部分(不需要而不是在链接答案中完成,因为i
在DT
范围内进行评估{1}}):
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")
答案 1 :(得分:3)
我从来没有使用过data.table包,所以请原谅我,如果我在这里错过了标记,但我想我已经得到了它。这里有很多事情要做。首先阅读do.call
,它允许您以某种非传统方式评估任何函数,其中参数由提供的列表指定(其中列表中的每个元素在位置上与函数参数匹配,除非明确命名)。另请注意,我必须指定min(df$variable)
而不是min(variable)
。请阅读Hadley's page on scoping以了解此问题。
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]