我在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%。我的应用程序
此处的尺寸
n
和length(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
。