首先是我所看到的一个简单例子,然后是一些关于我为什么要做我正在做的事情的背景。
dt = data.table(i=rep(1:3, each=4), t=rep(1:4, times=3), x=runif(12))
dt[, .(sum=sum(x), cnt=.N), keyby=.(i)] # works as expected
# i sum cnt
# 1: 1 2.932400 4
# 2: 2 1.483940 4
# 3: 3 2.113194 4
dt[, .(sum=sum(x), cnt=.N), keyby=list(i)] # same as above
# let j and keyby be specified by user, optionally NULL
j_str = parse(text=".(sum=sum(x), cnt=.N)")
by_str = parse(text="keyby=.(i)")
dt[, eval(j_str), eval(by_str)] # could not find function .
# Error in .(i) : could not find function "."
by_str = parse(text="keyby=list(i)")
dt[, eval(j_str), eval(by_str)] # correct results, but not correct column names
# keyby sum cnt
# 1: 1 2.932400 4
# 2: 2 1.483940 4
# 3: 3 2.113194 4
注意两个问题,我最关心的是第二个(错误的列名)。
我特别喜欢做的只是传入一个在data.table []中得到评估的字符串,但我无法让它工作,只有i,j等单独
为什么我这样做,简化版本是我正在编写一个执行此评估的函数。
stupidfnc = function(dt, j_str, by_str) {
return(dt[, eval(j_str), eval(by_str)])
}
更长的答案是我想循环遍历文件,聚合,rbind,然后再次聚合。但是,聚合数据的完整列表太大而无法容纳在内存中。因此,我正在做一些循环,rbinding,聚合,更多循环,rbinding,聚合,然后聚合聚合,然后循环.....我有一个函数,允许我写一个函数来做到这一点以灵活的方式,无需每次都重写循环。我这样做了很多,并且处理各种循环级别是一个比实际应该更高的认知负担。所以我希望像这样的函数有用。
该功能如下。
#' find z the maximum integer divisor of x st z <= sqrt(x)
#'
#' you can find y = x / z easily enough
#' useful for rbind'ing in chunks w/ a merge or collapse
integer_approx_sqrt = function(x) {
upper = floor(sqrt(x))
for (cand in upper:1) {
if ((x %% cand) == 0) {
break
}
}
return(cand)
}
#' loop over l, apply FUN, and aggregate with j_aggr by by_agg
#'
#' todo
mclapply_rbind_aggr = function(l, FUN, j_aggr, by_aggr, mc.cores=1,
mc.preschedule=F, chunksize=0, ...) {
if (chunksize == 0) {
chunksize = integer_approx_sqrt(length(l))
}
if (length(l) <= chunksize | chunksize == 1) {
dtl = mclapply(l, FUN=FUN, mc.cores=mc.cores,
mc.preschedule=mc.preschedule, ...)
} else {
dtl = lapply(splitIndices(length(l), chunksize),
function(indcs) {
rbindlist(mclapply(indcs, FUN=FUN, mc.cores=mc.cores,
mc.preschedule=mc.preschedule, ...))[,
eval(parse(text=j_aggr)), eval(parse(text=by_aggr))]})
}
return(rbindlist(dtl)[, eval(parse(text=j_aggr)), eval(parse(text=by_aggr))])
}