Изменения

R:Измерение времени выполнения выражений

6433 байта добавлено, 05:18, 23 января 2014
м
Пакет rbenchmark
== Пакет rbenchmark ==
 
Основа пакета {{Inline-code|rbenchmark|lang="rsplus"}} - функция {{Inline-code|benchmark()|lang="rsplus"}}. Данная функция работает следующим образом: указанные в качестве аргументов выражения выполняются заданное количество раз (по умолчанию 100) и вычисляется время, затраченное на выполнение всех попыток. В качестве аргументов функции {{Inline-code|benchmark()|lang="rsplus"}} необходимо передать выражения или функции, а также количество повторений, передаваемых аргументом replications<ref>Анализа функции {{Inline-code|benchmark()|lang="rsplus"}} показал, что, данная функция использует {{Inline-code|system.time()|lang="rsplus"}} и {{Inline-code|replicate()|lang="rsplus"}}, рассмотренные в предыдущем разделе.</ref>.
 
Для примера возьмём несколько способов расчёта среднего арифметического для сгенерированного массива данных.
 
Использованные нами способы - функции векторизованных вычислений ({{Inline-code|apply()|lang="rsplus"}}, {{Inline-code|vapply()|lang="rsplus"}}), стандартный цикл и специальная функция вычисления средних по столбцам {{Inline-code|ColMeans()|lang="rsplus"}}. Представим эти способы в виде самостоятельных функций для удобства их вызова при работе с {{Inline-code|benchmark()|lang="rsplus"}}:
 
<syntaxhighlight lang="rsplus">
> x <- replicate(10, rnorm(10^6L))
</syntaxhighlight>
 
<syntaxhighlight lang="rsplus">
CMApply <- function(x) {
apply(x, 2, mean)
}
 
CMVapply <- function(x) {
vapply(seq_len(ncol(x)), function(i) mean(x[, i]), FUN.VALUE = numeric(1))
}
 
CMLoop <- function(x) {
n.vars <- ncol(x)
res <- double(n.vars)
for (i in seq_len(n.vars))
res[i] <- mean(x[, i])
return(res)
}
 
CMLoopVec <- function(x) {
n.vars <- ncol(x)
n <- nrow(x)
res <- double(n.vars)
for (i in seq_len(n.vars))
res[i] <- sum(x[, i]) / n
return(res)
}
</syntaxhighlight>
 
Убедимся, что функции возвращают одинаковый результат. Сделать это можно с помощью функций {{Inline-code|identical()|lang="rsplus"}} или {{Inline-code|all.equal()|lang="rsplus"}}:
 
<syntaxhighlight lang="rsplus">
> identical(CMApply(x), CMVapply(x), CMLoop(x), CMLoopVec(x), ColMeans(x))
</syntaxhighlight>
 
Теперь, подключив пакет rbenchmark, мы можем сравнить время работы каждого из выбранных нами способов вычисления средних по столбцам:
 
<syntaxhighlight lang="rsplus">
> library(rbenchmark)
> benchmark(CMApply(x), CMVapply(x), CMLoop(x),
CMLoopVec(x), ColMeans(x), replications = 100)
</syntaxhighlight>
 
Наиболее важны для нас в выводе функции {{Inline-code|benchmark()|lang="rsplus"}} столбцы elapsed и relative. Столбец elapsed показывает время, затраченное на выполнение интересующей нас функции. Как видим из примера, самыми медленными оказались функции {{Inline-code|CMApply()|lang="rsplus"}} и {{Inline-code|CMLoop()|lang="rsplus"}}, а самой быстрой {{Inline-code|ColMeans()|lang="rsplus"}}, причём превосходит остальные по скорости выполнения как минимум в 7 раз.
 
Показатель relative дает информацию о разнице во времени относительно самого быстрого выражения (в нашем случае это {{Inline-code|ColMeans()|lang="rsplus"}}), т.е. время самого быстрого выражения берётся за единицу, и рассчитывается относительное время для остальных выражений.
 
Для более удобного просмотра можно отфильтровать вывод функции {{Inline-code|benchmark()|lang="rsplus"}} с помощью аргумента columns. Также может быть полезен аргумент order, позволяющий отсортировать вывод по любому из столбцов. Для примера зададим набор показателей, которые мы хотим включить в таблицу (в данном случае это «test», «replications», «elapsed», «relative»), и отсортируем выдачу по столбцу «elapsed» по возрастанию значений:
 
<syntaxhighlight lang="rsplus">
> benchmark(CMApply(x), CMVapply(x), CMLoop(x), CMLoopVec(x), ColMeans(x),
replications = 100, order = "relative",
columns = c("test", "replications", "elapsed", "relative"))
</syntaxhighlight>
 
Таким образом, сравнив несколько альтернатив решения нашей задачи, мы можем сделать обоснованный выбор в пользу наиболее эффективного варианта.
 
Чтобы не указывать нужные столбцы каждый раз, когда используется функция {{Inline-code|benchmark()|lang="rsplus"}}, можно закрепить заданный формат выдачи результатов (далее используется именно такой формат вывода, с сортировкой по столбцу «relative»). Для этого следует воспользоваться функцией {{Inline-code|formals()|lang="rsplus"}}:
 
<syntaxhighlight lang="rsplus">
> formals(benchmark)$columns <- c("test", "replications", "elapsed", "relative")
> formals(benchmark)$order <- "relative"
</syntaxhighlight>
== Пакет microbenchmark ==