Cálculo eficiente de una combinación lineal de columnas data.table.
yo tengonc
columnas en una tabla de datos, ync
Scalars en un vector. Quiero tomar uncombinación lineal de las columnas, pero no sé de antemano qué columnas usaré.¿Cuál es la forma más eficiente de hacer esto?
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])
maneras de hacerloSupongamos que quiero usar las primeras cuatro columnas. Puedo escribir manualmente:
DT[,list(cf['A']*A+cf['B']*B+cf['C']*C+cf['D']*D)]
Puedo pensar en dos formas automáticas (que funcionan sin saber que A-E debe usarse todas):
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]
evaluación comparativaEspero elas.matrix
para hacer la segunda opción lenta, y realmente no tienen intuición para la velocidad deMap
-Reduce
combinaciones
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
Obtengo de un 5% a un 40% de desaceleración en relación con el enfoque manual cuando repito elbenchmark
llamada.
Las dimensiones aquí -n
ylength(mycols)
- están cerca de lo que estoy trabajando, pero ejecutaré estos cálculos muchas veces, alterando el vector de coeficiente,cf
.