Как часть алгоритма подбора модели, мне нужно взять множитель dr aws из многомерного нормального распределения.
У dr aws есть вложенная структура, поэтому для алгоритма подбора модели мне нужно взять, например, 1000 dr aws для 5 единиц, каждая из которых содержит 500 единиц. Таким образом, всего 1000 * 5 * 500 др aws в этом примере. Для каждой из 1000 драм aws ковариационная матрица sigma
для многомерного распределения будет отличаться. Для каждой из 5 * 500 единиц в пределах 1000 др aws средний вектор mu
будет различным.
Я кодировал приведенный ниже пример, который сначала устанавливает пример данных интересующей меня структуры, а затем генерирует dr aws в нужном мне формате.
#set up
library(mvnfast) #for rmvn function
nPar<-1000
K<-5
n<-rep(500,K)
mu<-lapply(1:nPar,function(u){
lapply(1:K,function(v){
do.call(rbind,lapply(1:n[v],function(w){
runif(1)*c(0.3,0.5)
}))
})
})
sigmamats<-lapply(1:nPar,function(u){
runif(1)*matrix(c(0.5,0.1,0.1,0.5),nrow=2,ncol=2)
})
#code needing speeding up
system.time(test<-lapply(1:nPar,function(u){
lapply(1:K,function(v){
do.call(rbind,lapply(1:n[v],function(w){
rmvn(n=1,
mu=mu[[u]][[v]][w,],
sigma=sigmamats[[u]])
}))
})
}))
# user system elapsed
# 122.01 78.49 204.06
Я пробовал несколько различных перестановок (например, сначала использовал rbind и удалял слой вложенности w
, так что в этом примере второе значение lapply работает от 1 до 2500, но это не сильно ускоряло код при все.
Мне нужно сократить это время, так как это будет оценено не менее 200 раз в моем алгоритме подбора модели. Размеры на каждом уровне (nPar
, K
, n
) могут меняется в зависимости от оцениваемых данных.
Буду признателен за любые советы по ускорению этого процесса.
РЕДАКТИРОВАТЬ результаты профилирования:
Rprof(tmp<-tempfile())
test<-lapply(1:nPar,function(u){
lapply(1:K,function(v){
do.call(rbind,lapply(1:n[v],function(w){
rmvn(n=1,
mu=mu[[u]][[v]][w,],
sigma=sigmamats[[u]])
}))
})
})
Rprof()
summaryRprof(tmp)
$by.self
self.time self.pct total.time
".Call" 153.16 75.27 161.84
"rmvn" 21.32 10.48 190.90
"matrix" 6.20 3.05 6.46
"FUN" 5.44 2.67 203.48
"lapply" 4.96 2.44 203.48
"getCallingDLLe" 4.84 2.38 8.68
"get0" 3.44 1.69 3.44
"<Anonymous>" 1.66 0.82 1.66
"length" 0.88 0.43 0.88
"is.matrix" 0.48 0.24 0.48
"do.call" 0.46 0.23 203.40
"is.numeric" 0.32 0.16 0.32
"is.atomic" 0.26 0.13 0.26
"match.fun" 0.06 0.03 0.06
total.pct
".Call" 79.54
"rmvn" 93.82
"matrix" 3.17
"FUN" 100.00
"lapply" 100.00
"getCallingDLLe" 4.27
"get0" 1.69
"<Anonymous>" 0.82
"length" 0.43
"is.matrix" 0.24
"do.call" 99.96
"is.numeric" 0.16
"is.atomic" 0.13
"match.fun" 0.03
$by.total
total.time total.pct
"FUN" 203.48 100.00
"lapply" 203.48 100.00
"do.call" 203.40 99.96
"rmvn" 190.90 93.82
".Call" 161.84 79.54
"getCallingDLLe" 8.68 4.27
"matrix" 6.46 3.17
"get0" 3.44 1.69
"<Anonymous>" 1.66 0.82
"length" 0.88 0.43
"is.matrix" 0.48 0.24
"is.numeric" 0.32 0.16
"is.atomic" 0.26 0.13
"match.fun" 0.06 0.03
"cmpfun" 0.02 0.01
"compiler:::tryCmpfun" 0.02 0.01
"doTryCatch" 0.02 0.01
"findLocalsList" 0.02 0.01
"findLocalsList1" 0.02 0.01
"funEnv" 0.02 0.01
"make.functionContext" 0.02 0.01
"tryCatch" 0.02 0.01
"tryCatchList" 0.02 0.01
"tryCatchOne" 0.02 0.01
self.time self.pct
"FUN" 5.44 2.67
"lapply" 4.96 2.44
"do.call" 0.46 0.23
"rmvn" 21.32 10.48
".Call" 153.16 75.27
"getCallingDLLe" 4.84 2.38
"matrix" 6.20 3.05
"get0" 3.44 1.69
"<Anonymous>" 1.66 0.82
"length" 0.88 0.43
"is.matrix" 0.48 0.24
"is.numeric" 0.32 0.16
"is.atomic" 0.26 0.13
"match.fun" 0.06 0.03
"cmpfun" 0.00 0.00
"compiler:::tryCmpfun" 0.00 0.00
"doTryCatch" 0.00 0.00
"findLocalsList" 0.00 0.00
"findLocalsList1" 0.00 0.00
"funEnv" 0.00 0.00
"make.functionContext" 0.00 0.00
"tryCatch" 0.00 0.00
"tryCatchList" 0.00 0.00
"tryCatchOne" 0.00 0.00
$sample.interval
[1] 0.02
$sampling.time
[1] 203.48
РЕДАКТИРОВАТЬ # 2 - в идеале этот код в конечном итоге go будет превращен в пакет, и поэтому мне нужен способ ускорить этот процесс, который может присутствовать в коде, вносящем вклад в пакет R