Повышение производительности моделирования — разбор занимает слишком много времени

#r #performance #parsing #profiling

#r #Производительность #синтаксический анализ #профилирование

Вопрос:

Я делаю несколько симуляций с разными распределениями вероятностей и с разными параметрами. Пример: распределение — нормальное, среднее значение параметра и sd. Среднее значение исправлено (например, 0), а sd изменяется, например, с 1 на 5. Я написал некоторую функцию для решения этой проблемы, простая версия, которая даст вам представление, приведена ниже:

 test <- function(x, fixed, value, changed, seq){
    expr <- eval(parse(text=stri_flatten(c(fixed,"=",value))))
    for(i in seq_along(seq)){
        expr2 <- eval(parse(text=stri_flatten(c(changed,"=",seq[i]))))
        y <- dnorm(x, expr, expr2)
        sqrt(y*y   y*y)
    }
}
  

В моей функции анализ занимает половину времени моделирования (13 секунд из 25 секунд). Мне нужно это улучшить, есть идеи, как? Вы можете запустить функцию Rprof и проверить результат:

 {Rprof();test(-10:10,"mean",0,"sd",seq(1,5,length.out = 1001));Rprof(NULL);}
summaryRprof()
  

Rprof результаты моего моделирования (только часть)

 summaryRprof()
$by.self
                       self.time self.pct total.time total.pct
"parse"                    13.48    53.71      15.42     61.43
"ifelse"                    2.26     9.00      23.64     94.18
"structure"                 1.56     6.22       2.66     10.60
".External"                 0.80     3.19      17.90     71.31
"$<-"                       0.54     2.15       0.54      2.15
"options"                   0.52     2.07       0.54      2.15
"makeRestartList"           0.50     1.99       1.98      7.89
"c"                         0.46     1.83       0.46      1.83
"match"                     0.40     1.59       0.40      1.59
"doWithOneRestart"          0.38     1.51       1.60      6.37
"eval"                      0.32     1.27      15.84     63.11
"stopifnot"                 0.26     1.04       0.34      1.35
".Call"                     0.26     1.04       0.28      1.12
"phirsch"                   0.24     0.96      24.46     97.45
"t"                         0.24     0.96       0.26      1.04
"any"                       0.24     0.96       0.24      0.96
"pbeta"                     0.22     0.88      22.00     87.65
"list"                      0.20     0.80       0.20      0.80
"%in%"                      0.16     0.64       0.38      1.51
"^"                         0.14     0.56       0.14      0.56
"floor"                     0.14     0.56       0.14      0.56
  

Одна из идей ускорить это — использовать внутреннюю функцию разбора:

 text <- "a <- 5"
internalParse <- function(x) .Internal(parse(stdin(), NULL, x, NULL, NULL, "unknown"))
microbenchmark(parse(text=text), internalParse(text))
## Unit: microseconds
##                 expr     min       lq  median       uq       max neval
##   parse(text = text) 146.388 196.4995 254.677 333.5975 11487.912   100
##  internalParse(text)  75.639  96.5910 115.239 135.3885  5031.508   100
  

Комментарии:

1. PS вы действительно имели в виду y*y y*y , а не x*x y*y ?

Ответ №1:

Как насчет

 test2 <- function(x, fixed, value, changed, seqvec){
    argList0 <- setNames(list(value),fixed)
    for(i in seq_along(seqvec)){
        argList <- c(list(x),argList0,setNames(list(seqvec[i]),changed))
        y <- do.call(dnorm,argList)
        sqrt(y*y   y*y)
    }
}
  

(Вероятно, вызывать числовой вектор — плохая идея seq : большую часть времени он будет работать, но при сбое произойдет сбой очень запутанным способом!)

Тесты:

 microbenchmark(test(-10:10,"mean",0,"sd",seq(1,5,length.out = 1001)),test2(-10:10,"mean",0,"sd",seq(1,5,length.out = 1001)),times = 10)
Unit: milliseconds
       expr       min        lq    median        uq       max neval
  test(...) 638.06613 643.23257 663.01249 682.08094 740.33703    10
 test2(...)  21.71302  22.07522  23.23993  28.96877  30.46197    10
  

Я думаю

 outer(-10:10,1:5,dnorm,mean=0)
  

должно быть намного быстрее, но не совсем ясно, что вы на самом деле пытаетесь сделать.

Комментарии:

1. Добавлены некоторые тесты. Ваши решения выглядят действительно многообещающими 🙂

2. Время моделирования сократилось с 25 секунд до 9 секунд! Большое вам спасибо!