Hao*_*Hao 14 performance benchmarking if-statement r
当我最近重新阅读Hadley的Advanced R时,我注意到他在第6章中说过`if`可以用作一个函数
`if`(i == 1, print("yes"), print("no"))
(如果你手头有实体书,那就是第80页)
我们知道这ifelse很慢(ifelse每次都会真正计算它的两个向量吗?它是否很慢?)因为它会评估所有参数.将`if`是一个很好的替代品,if似乎只评估TRUE参数(这只是我的假设)?
更新:基于@Benjamin和@Roman的答案以及@Gregor和其他许多人的评论,ifelse似乎是矢量化计算的更好解决方案.我在这里接受@ Benjamin的回答,因为它提供了更全面的比较和社区健康.但是,这两个答案(以及评论)都值得一读.
Ben*_*min 17
这是一个基于Roman答案的扩展评论,但我需要代码实用程序来解释:
罗马是正确的,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 )],
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
Run Code Online (Sandbox Code Playgroud)
一些编辑:感谢弗兰克和理查德斯克里文注意到我的缺点.
正如您所看到的,将向量分解为适合传递的if过程是一个耗时的过程,并且最终比运行速度慢ifelse(这可能是没有人为实现我的解决方案而烦恼的原因).
如果你真的急于提高速度,你可以使用ifelse3上面的方法.或者更好的是,弗兰克不那么明显*但是很棒的解决方案.
yes和no有长度为1,否则你会想坚持ifelse3if是一个通过.Primitive接口调用的原始(ifelse编译)函数,而是R字节码,所以看起来if会更快.运行一些快速基准测试
> microbenchmark(`if`(TRUE, "a", "b"), ifelse(TRUE, "a", "b"))
Unit: nanoseconds
expr min lq mean median uq max neval cld
if (TRUE) "a" else "b" 46 54 372.59 60.0 68.0 30007 100 a
ifelse(TRUE, "a", "b") 1212 1327 1581.62 1442.5 1617.5 11743 100 b
> microbenchmark(`if`(FALSE, "a", "b"), ifelse(FALSE, "a", "b"))
Unit: nanoseconds
expr min lq mean median uq max neval cld
if (FALSE) "a" else "b" 47 55 91.64 61.5 73 2550 100 a
ifelse(FALSE, "a", "b") 1256 1346 1688.78 1460.0 1677 17260 100 b
Run Code Online (Sandbox Code Playgroud)
似乎如果不考虑实际分支中的代码,if至少要快20倍ifelse.但请注意,这并未考虑正在测试的表达式的复杂性以及可能的优化.
更新:请注意,此快速基准代表了ifvs的一个非常简化且有些偏见的用例ifelse(正如评论中所指出的).虽然它是正确的,但它代表了ifelse用例,因为本杰明的答案似乎提供了更公平的比较.
| 归档时间: |
|
| 查看次数: |
4289 次 |
| 最近记录: |