我在data.table中有nc列,在向量中有nc标量。我想在列中使用linear combination,但是我不提前知道将使用哪个列。最有效的方法是什么?

建立

require(data.table)
set.seed(1)

n  <- 1e5
nc <- 5
cf <- setNames(rnorm(nc),LETTERS[1:nc])
DT <- setnames(data.table(replicate(nc,rnorm(n))),LETTERS[1:nc])


做到的方式

假设我要使用前四列。我可以手动编写:

DT[,list(cf['A']*A+cf['B']*B+cf['C']*C+cf['D']*D)]


我可以想到两种自动方式(这种方式在不知道都应使用A-E的情况下起作用):

mycols <- LETTERS[1:4] # the first four columns
DT[,list(as.matrix(.SD)%*%cf[mycols]),.SDcols=mycols]
DT[,list(Reduce(`+`,Map(`*`,cf[mycols],.SD))),.SDcols=mycols]


基准测试

我希望as.matrix会使第二个选项变慢,并且对于Map-Reduce组合的速度确实没有直觉。

require(rbenchmark)
options(datatable.verbose=FALSE) # in case you have it turned on

benchmark(
    manual=DT[,list(cf['A']*A+cf['B']*B+cf['C']*C+cf['D']*D)],
    coerce=DT[,list(as.matrix(.SD)%*%cf[mycols]),.SDcols=mycols],
    maprdc=DT[,list(Reduce(`+`,Map(`*`,cf[mycols],.SD))),.SDcols=mycols]
)[,1:6]

    test replications elapsed relative user.self sys.self
2 coerce          100    2.47    1.342      1.95     0.51
1 manual          100    1.84    1.000      1.53     0.31
3 maprdc          100    2.40    1.304      1.62     0.75


相对于手动方法,当我重复benchmark调用时,速度降低了5%到40%。

我的应用程序

此处的尺寸nlength(mycols)接近我正在使用的尺寸,但是我将多次运行这些计算,并更改系数矢量cf

最佳答案

对我来说,这几乎比您的手动版本快2倍:

Reduce("+", lapply(names(DT), function(x) DT[[x]] * cf[x]))

benchmark(manual = DT[, list(cf['A']*A+cf['B']*B+cf['C']*C+cf['D']*D)],
          reduce = Reduce('+', lapply(names(DT), function(x) DT[[x]] * cf[x])))
#    test replications elapsed relative user.self sys.self user.child sys.child
#1 manual          100    1.43    1.744      1.08     0.36         NA        NA
#2 reduce          100    0.82    1.000      0.58     0.24         NA        NA


要仅遍历mycols,请在names(DT)中将mycols替换为lapply

07-25 21:59