`if`比ifelse更快? [英] Is `if` faster than ifelse?

查看:153
本文介绍了`if`比ifelse更快?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我最近重新阅读Hadley的Advanced R时,我注意到他在第6章中说过`if` 可以用作
之类的函数
`if`(i == 1,print(yes),print(no))

(如果你有实体书,它在第80页上)

When I was re-reading Hadley's Advanced R recently, I noticed that he said in Chapter 6 that `if` can be used as a function like `if`(i == 1, print("yes"), print("no")) (If you have the physical book in hand, it's on Page 80)

我们知道 ifelse 很慢( ifelse是否真的计算了它的两个向量每一次?慢吗?)因为它评估所有论点。将`if` 替换为,如果似乎只评估 TRUE 参数(这只是我的假设)?

We know that ifelse is slow (Does ifelse really calculate both of its vectors every time? Is it slow?) as it evaluates all arguments. Will `if` be a good alternative to that as if seems to only evaluate TRUE arguments (this is just my assumption)?

更新:根据@Benjamin和@Roman的答案以及@Gregor和其他许多人的评论, ifelse 似乎是矢量化计算的更好解决方案。我正在接受@ Benjamin的回答,因为它提供了更全面的比较和社区健康。但是,两个答案(和评论)都值得一读。

Update: Based on the answers from @Benjamin and @Roman and the comments from @Gregor and many others, ifelse seems to be a better solution for vectorized calculations. I'm taking @Benjamin's answer here as it provides a more comprehensive comparison and for the community wellness. However, both answers(and the comments) are worth reading.

推荐答案

这是罗马答案的扩展评论,但我需要代码实用程序来解释:

This is more of an extended comment building on Roman's answer, but I need the code utilities to expound:

罗马是正确的如果 ifelse 更快,但我是在如果的速度提升不是特别有趣的印象下,因为它不是可以通过矢量化轻松利用的东西。也就是说,当 cond 如果仅优于 ifelse $ c> / test 参数长度为1。

Roman is correct that if is faster than ifelse, but I am under the impression that the speed boost of if isn't particularly interesting since it isn't something that can easily be harnessed through vectorization. That is to say, if is only advantageous over ifelse when the cond/test argument is of length 1.

考虑以下函数,这是一个无可否认的弱尝试vectorizing if ,而不会产生评估 yes no 条件为 ifelse

Consider the following function which is an admittedly weak attempt at vectorizing if without having the side effect of evaluating both the yes and no conditions as ifelse does.

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注意到我的短信omings。

SOME EDITS: Thanks to Frank and Richard Scriven for noticing my shortcomings.

正如您所看到的,如果是分解向量以便传递给的过程是一个耗时的过程,最终比运行 ifelse 慢(这可能是为什么没有人费心去实现我的解决方案)。

As you can see, the process of breaking up the vector to be suitable to pass to if is a time consuming process and ends up being slower than just running ifelse (which is probably why no one has bothered to implement my solution).

如果您真的非常渴望提高速度,可以使用上面的 ifelse3 方法。或者更好的是,弗兰克不那么明显*但很棒的解决方案。

If you're really desperate for an increase in speed, you can use the ifelse3 approach above. Or better yet, Frank's less obvious* but brilliant solution.


  • '不太明显'我的意思是,我花了两秒钟才意识到什么他做到了。根据下面nicola的评论,请注意,这只适用于没有长度为1,否则你将会想坚持 ifelse3

  • by 'less obvious' I mean, it took me two seconds to realize what he did. And per nicola's comment below, please note that this works only when yes and no have length 1, otherwise you'll want to stick with ifelse3

这篇关于`if`比ifelse更快?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆