这更像是基于 Roman 的回答的扩展评论,但我需要代码实用程序来说明:
Roman 说 if 比 ifelse 快是正确的,但我的印象是 if 的速度提升并不是特别有趣,因为它不是可以通过矢量化轻松利用的东西。也就是说,if 仅在 cond/test 参数长度为 1 时优于 ifelse。
考虑以下函数,它在矢量化 if 方面是一个公认的弱尝试,而不会像 ifelse 那样评估 yes 和 no 条件。
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 )],
fourth_modified = c(x, x^2)[seq_along(x) + length(x) * (x < 0)]
)
Unit: microseconds
expr min lq mean median uq max neval cld
standard 52.198 56.011 97.54633 58.357 68.7675 1707.291 100 ab
modified 91.787 93.254 131.34023 94.133 98.3850 3601.967 100 b
modified_apply 645.146 653.797 718.20309 661.568 676.0840 3703.138 100 c
third 20.528 22.873 76.29753 25.513 27.4190 3294.350 100 ab
fourth 15.249 16.129 19.10237 16.715 20.9675 43.695 100 a
fourth_modified 19.061 19.941 22.66834 20.528 22.4335 40.468 100 a
一些编辑:感谢 Frank 和 Richard Scriven 注意到我的缺点。
如您所见,将向量分解为适合传递给if 的过程是一个耗时的过程,并且最终比仅运行ifelse 慢(这可能是为什么没有人费心实施我的解决方案)。
如果您真的非常渴望提高速度,可以使用上面的ifelse3 方法。或者更好的是,弗兰克的不那么明显*但出色的解决方案。
- “不太明显”我的意思是,我花了两秒钟才意识到他做了什么。根据下面 nicola 的评论,请注意,这仅在
yes 和 no 的长度为 1 时有效,否则您将要坚持使用 ifelse3