Я делаю что-то вроде этого

library(microbenchmark)
library(tidyverse)

f1 = function(n=100) rnorm(n)

f2 = function(n=100, shape1=1, shape2=0.1) rbeta(n, shape1, shape2)

f3 = function(n=100, shape=1) rgamma(n, shape)

maxdif = 1e6
mb = microbenchmark(f1(100), f2(100), f3(100), times=1)
if(max(abs(mb$time - lead(mb$time)), na.rm=TRUE)<maxdif) mb = 
  microbenchmark(f1(100), f2(100), f3(100), times=10)
mb$time
# [1] 1927396 1876079 1660118   32074   20528   42338   25659   23094   35923   37633
# [11]   16251   39344   27797   38061   13258   12830   38061   13685   13258   23094
# [21]   13686   25232   37633   24377   20528   12830   38061   14113   12402   35495

Пока мне все ясно и как положено. Однако, если я добавлю к нему функцию

fComp = function(..., times, maxdif){
  mb = microbenchmark(..., times=1)
  if(max(abs(mb$time - lead(mb$time)), na.rm=TRUE)<maxdif) mb = 
      microbenchmark(..., times=times)
  mb
}

mb = fComp(f1(100), f2(100), f3(100), times=10, maxdif = 1e6)
mb$time
# [1]  5988 29508   856   429   429     1     1     1   428     0   428   428     0
# [14]   428     1     1   428     0     1     0     1   429     1     1     0   428
# [27]     0   428     1   429

Происходит что-то странное.

Я предполагаю, что речь идет о передаче параметра .... К сожалению, я не знаю, как правильно декодировать ..., чтобы получить желаемый (как указано выше) эффект.

Буду признателен за любую подсказку.

2
blrun 11 Окт 2021 в 21:25

2 ответа

Лучший ответ

Похоже, проблема связана с двойным использованием .... Я думаю, что он пытается предотвратить многократную оценку выражений, что, возможно, и есть то, что вы хотите, но в случае тестирования производительности вы действительно хотите многократно оценивать одно и то же выражение. Вот работа вокруг

fComp = function(..., times, maxdif){
  exprs <- match.call(expand.dots = FALSE)$...
  mb = microbenchmark(list=exprs, times=1)
  if(max(abs(mb$time - lead(mb$time)), na.rm=TRUE)<maxdif) mb = 
    microbenchmark(list=exprs, times=times)
  mb
}

Мы используем match.call, чтобы получить неоцененные выражения, переданные в .... Затем мы передаем эти параметры в microbenchmark() через параметр list=, а не с помощью .... Кажется, это позволяет избежать такой оптимизации.

Этот метод также сохранил имена выражений в выводе

fComp(f1(100), f2(100), f3(100), times=10, maxdif = 1e6)
Unit: microseconds
    expr  min   lq  mean median   uq  max neval
 f1(100)  8.4  8.7  9.29   9.05  9.6 11.2    10
 f2(100) 25.1 25.7 28.40  25.95 27.5 46.9    10
 f3(100) 13.5 16.3 18.09  17.85 20.3 23.5    10
2
MrFlick 11 Окт 2021 в 18:49

Один из способов - изменить порядок последнего аргумента ..., и он работает.

fComp = function(times, maxdif, ...){
  mb = microbenchmark(times=1, ...)
  if(max(abs(mb$time - lead(mb$time)), na.rm=TRUE)<maxdif) mb = 
      microbenchmark(times=times, ...)
  mb
}

-тестирование

fComp(times=10, maxdif = 1e6, f1(100), f2(100), f3(100))
Unit: microseconds
 expr      min       lq     mean   median       uq      max neval
  ..1 1957.235 1957.235 1957.235 1957.235 1957.235 1957.235     1
  ..2  101.801  101.801  101.801  101.801  101.801  101.801     1
  ..3  170.926  170.926  170.926  170.926  170.926  170.926     1
1
akrun 11 Окт 2021 в 18:29