ifelse是否适用于非矢量化情况,反之亦然?

时间:2011-11-18 23:10:34

标签: r

(背景信息:ifelse评估表达式的两个,即使只返回一个。编辑:这是一个不正确的声明。请参阅Tommy的回复)

有没有在非矢量化情况下使用ifelse有意义的例子?我认为,当我们不关心小的效率增益时,“可读性”可能是一个有效的答案,但除此之外,当使用ifelse时,它是否更快/等效/更好于其他方式if然后else可以完成这项工作吗?

同样,如果我有矢量化情况,ifelse总是最好的工具吗?两个表达式都被评估似乎很奇怪。逐个循环并执行正常if然后else是否更快?我猜它只有在评估表达式花了很长时间才有意义。还有其他不涉及显式循环的替代方案吗?

由于

2 个答案:

答案 0 :(得分:15)

首先,只有在测试向量中同时包含ifelseTRUE个元素时,FALSE才能 NOT 始终评估两个表达式。

ifelse(TRUE, 'foo', stop('bar')) # "foo"

在我看来:

ifelse 应在非矢量化情境中使用。在ifelse / if上使用else 始终更慢更容易出错

# This is fairly common if/else code
if (length(letters) > 0) letters else LETTERS

# But this "equivalent" code will yield a very different result - TRY IT!
ifelse(length(letters) > 0, letters, LETTERS)

在矢量化的情况下,ifelse可能是一个不错的选择 - 但要注意结果的长度和属性可能不是你所期望的(如上所述,我认为ifelse被打破了方面)。

以下是一个示例:tst的长度为5,并且有一个类。我希望结果长度为10并且没有类,但这不会发生什么 - 它会得到一个不兼容的类和长度为5!

# a logical vector of class 'mybool'
tst <- structure(1:5 %%2 > 0, class='mybool')

# produces a numeric vector of class 'mybool'!
ifelse(tst, 101:110, 201:210)
#[1] 101 202 103 204 105
#attr(,"class")
#[1] "mybool"

为什么我希望长度为10?因为R中的大多数函数“循环”较短的向量以匹配较长的:

1:5 + 1:10 # returns a vector of length 10.

...但是ifelse只循环yes / no参数以匹配tst参数的长度。

为什么我希望从测试对象中复制的类(和其他属性)?因为返回逻辑向量的<不会从其(通常是数字)参数复制类和属性。它没有这样做,因为它通常是非常错误的。

1:5 < structure(1:10, class='mynum') # returns a logical vector without class

最后,“自己动手”会更有效吗?好吧,ifelse似乎不像if这样的原语,它需要一些特殊的代码来处理NA。如果你没有NA,那么自己动手可能会更快。

tst <- 1:1e7 %%2 == 0
a <- rep(1, 1e7)
b <- rep(2, 1e7)
system.time( r1 <- ifelse(tst, a, b) )            # 2.58 sec

# If we know that a and b are of the same length as tst, and that
# tst doesn't have NAs, then we can do like this:
system.time( { r2 <- b; r2[tst] <- a[tst]; r2 } ) # 0.46 secs

identical(r1, r2) # TRUE

答案 1 :(得分:4)

关于你的第二点,你如何定义“最佳”?我认为ifelse()是更易读的解决方案之一,但可能并不总是最快的。具体来说,我发现写出布尔条件并将它们加在一起可以带来一些性能上的好处。这是一个简单的例子:

> x <- rnorm(1e6)
> system.time(y1 <- ifelse(x > 0,1,2))
   user  system elapsed 
   0.46    0.08    0.53 
> system.time(y2 <- (x > 0) * 1 + (x <= 0) * 2)
   user  system elapsed 
   0.06    0.00    0.06 
> identical(y1, y2)
[1] TRUE

因此,如果速度是您最关心的问题,那么布尔方法可能会更好。但是,对于我的大部分目的 - 我发现ifelse()足够快,很容易理解。你的里程可能会有很大不同。