Ответ 1
Это скорее расширенное построение комментариев по римскому ответу, но мне нужны утилиты кода для изложения:
Роман прав, что if
быстрее, чем ifelse
, но у меня создается впечатление, что ускорение скорости if
не особенно интересно, так как это не то, что можно легко использовать с помощью векторизации. То есть if
является преимущественным только при ifelse
, когда аргумент cond
/test
имеет длину 1.
Рассмотрим следующую функцию, которая является, по общему признанию, слабой попыткой векторизации if
без побочного эффекта оценки условий yes
и no
как ifelse
.
ifelse2 <- function(test, yes, no){
result <- rep(NA, length(test))
for (i in seq_along(test)){
result[i] <- `if`(test[i], yes[i], no[i])
}
result
}
ifelse2a <- function(test, yes, no){
sapply(seq_along(test),
function(i) `if`(test[i], yes[i], no[i]))
}
ifelse3 <- function(test, yes, no){
result <- rep(NA, length(test))
logic <- test
result[logic] <- yes[logic]
result[!logic] <- no[!logic]
result
}
set.seed(pi)
x <- rnorm(1000)
library(microbenchmark)
microbenchmark(
standard = ifelse(x < 0, x^2, x),
modified = ifelse2(x < 0, x^2, x),
modified_apply = ifelse2a(x < 0, x^2, x),
third = ifelse3(x < 0, x^2, x),
fourth = c(x, x^2)[1L + ( x < 0 )]
)
Unit: microseconds
expr min lq mean median uq max neval cld
standard 125.509 130.0545 809.50617 133.4265 136.5055 64762.881 100 ab
modified 1120.197 1153.4795 1223.87912 1182.8040 1248.1980 1575.313 100 b
modified_apply 902.022 921.6690 977.59717 934.4255 969.3220 2518.389 100 ab
third 39.588 42.5210 58.72267 44.2810 46.1865 1427.224 100 a
fourth 15.542 17.5950 33.91116 18.6215 20.0875 1431.916 100 a
НЕКОТОРЫЕ РЕДАКТОРЫ: Спасибо Фрэнку и Ричарду Скривену за то, что заметили мои недостатки.
Как вы можете видеть, процесс разбиения вектора, который подходит для перехода на if
, является трудоемким процессом и заканчивается медленнее, чем просто запуск ifelse
(что, вероятно, почему никто не потрудился реализовать мое решение).
Если вы действительно отчаянно нуждаетесь в увеличении скорости, вы можете использовать подход ifelse3
выше. Или еще лучше, Фрэнк менее очевидный *, но блестящее решение.
- "менее очевидным", я имею в виду, мне потребовалось две секунды, чтобы понять, что он сделал. Обратите внимание на то, что это работает только тогда, когда
yes
иno
имеют длину 1, в противном случае вы захотите придерживатьсяifelse3