2015-04-09 2 views
1

У меня есть функция, которая строит другую функцию в соответствии с некоторыми специфическими параметрами:`microbenchmark` функция, построенная с помощью функции фабрики

factory <- function(param) { 
    # some long computation… 
    cached.matrix = rnorm(param) 

    # return function that uses cached data 
    function(other) { 
     cached.matrix * cached.matrix + other 
    } 
} 

Теперь я хотел эталонные функции, порожденных factory функции для различных параметров с помощью microbenchmark упаковка. microbenchmark функция принимает выражение, а не функция, а после некоторых экспериментов я заметил, что следующий танец с do.call и call, кажется, работает:

params <- seq(5, 100, 5) 
list.of.expressions <- sapply(
    params, 
    function(param) call('do.call', factory(param), list(7))) 
names(list.of.expressions) <- sprintf("f%04d", params) 
mb.results <- microbenchmark(list=list.of.expressions, times=10) 

Есть более простой способ сбора результатов ориентира функций параметризованного как что, чем call('do.call', …)?

ответ

1

Я собираюсь показать еще один возможный маршрут. То, что вы делаете, это построить неоценимые выражения, в то время как я буду обертывать вызов microbenchmark в функцию и использовать outer для получения желаемого разбиения.

Я неявно предполагаю, что вы хотите перебрать два измерения (в вашем примере param и other). Я построил свою собственную функцию завода:

factory <- function(param) { 
    x <- rnorm(param) 
    function(mat) { 
    t(x) %*% mat %*% x 
    } 
} 

Теперь я хотел бы, чтобы перебрать param и mat. Чтобы сделать его еще более интересным, пусть mat зависит от param как-то. Если это не так, просто игнорируйте mat как функцию: это может быть вектор.

params <- seq(10, 50, 10) 
mat1 <- function(param) {diag(param)} 
mat2 <- function(param) {matrix(runif(param^2), param)} 

Вот функция, которая будет идти в outer, а сам вызов:

test_factory_med <- Vectorize(function(param, matf) { 
     summary(microbenchmark(factory(param)(matf(param))))$median 
}) 
median_tests <- outer(params, c(mat1, mat2), 
         FUN = function(p, m) test_factory_med(p, m)) 

colnames(median_tests) <- c("mat1", "mat2") 
rownames(median_tests) <- params 
median_tests 
#  mat1  mat2 
#10 15.3150 22.6720 
#20 18.6180 36.6355 
#30 22.2220 57.9560 
#40 27.3265 88.5860 
#50 32.7320 129.1250 

Вы можете сохранить полный набор информации из microbenchmark, возвращая список из него (со списком обертывания взломать от моего recent question):

test_factory_all <- Vectorize(function(param, matf) { 
    list(
    list(param = param, 
     matf = mat, 
     microbenchmark(factory(param)(matf(param))))) 
}) 

all_tests <- outer(params, c(mat1, mat2), 
        FUN = function(p, m) test_factory_all(p, m)) 
all_tests[1, 1] 

#[[1]] 
#[[1]]$param 
#[1] 10 
# 
#[[1]]$matf 
#function (param) 
#{ 
# diag(param) 
#} 
# 
#[[1]][[3]] 
#Unit: microseconds 
#      expr min  lq  mean median  uq max neval 
# factory(param)(matf(param)) 14.414 15.315 17.17081 15.916 16.516 88.586 100 

Edit: в ответ на комментарий ниже, вот как вы можете измерить только звонки functi которые вышли с завода.

# exclude costs for running factory 
test_factory_med1 <- Vectorize(function(param, matf) { 
     f <- factory(param) 
     summary(microbenchmark(f(matf(param))))$median 
}) 

# exclude costs for both running factory and constructing parameter 
test_factory_med2 <- Vectorize(function(param, matf) { 
     f <- factory(param) 
     m <- matf(param) 
     summary(microbenchmark(f(m)))$median 
}) 
+0

Хм, я не хочу сравнивать заводскую функцию, просто результат. Не будет 'microbenchmark (factory (param) (matf (param)))' count time как заводского вызова, так и вызова функции возврата? – liori

+0

@ liori Да, это будет. Разве это не то, что вам нужно? Что вы подразумеваете под «эталоном только результата»? – tonytonov

+0

Если вы заинтересованы только в сравнительном анализе окончательного вызова (за вычетом стоимости для 'factory (param)', я полагаю, это то, что вы имеете в виду выше), поместите 'factory (param)' out of microbenchmark': 'fp < - фабрика (param); microbenchmark (fp (matf (param))) – tonytonov