> a <- factor(1:3)
> b <- c(0,1,2)
> ifelse(b == 0, 5, a[b])
[1] 5 2 1
我希望看到5,1,2
原因是a[b]
实际返回1, 2
,其长度与a
不同,因此ifelse
的结果因回收而损坏。
我可以用ifelse
写if...else
,但效率很低。处理它的常用方法是什么?
答案 0 :(得分:3)
此解决方案产生正确的答案:
a <- factor(1:3)
b <- c(0,1,2)
a = as.numeric(a)
zero_logical = b != 0 # Precompute because if a contains a zero, this will also be replaced by 5
b[zero_logical] <- a[b[zero_logical]]
b[!zero_logical] <- 5
b
[1] 5 1 2
此解决方案使用两个分配,一个用于b != 0
,另一个用于b == 0
,因此与显式循环相比,这应该非常快。
答案 1 :(得分:2)
没有将效率与保罗的回答进行比较,而是为了考虑这个(也许)特殊情况:
a <- factor(1:3)
b <- c(0,1,2)
a2 <- as.factor(c("5", a))
a2[b + 1]
# [1] 5 1 2
# Levels: 1 2 3 5
如果您正在寻找除b == 0
以外的任何其他内容,此方法很可能无效。
答案 2 :(得分:2)
b[b == 0] <- NA
ifelse(is.na(b), 5, a[b])
答案 3 :(得分:0)
以前的答案都使用a[_conditions_]
代替_conditions_(a[])
,这似乎对您的情况更好;这个答案也有相同的概念:)。
除了提到的其他方法之外,使用a[ifelse(, , b)]
而非ifelse(, , a[b])
之类的方法。我能想出的唯一解决方案是在a
处放大5
,因此可以使用a[ifelse(b == 0, which(a == 5), b)]
之类的内容。当然,a
必须在前面提到的电话之前重新分配。
为了避免更改a
并避免在您工作的环境中分配额外的变量(即a
的备份),您可以将所有内容包装在local
内;否则local
在答案中看起来很酷,可以避免:
a <- factor(1:3)
b <- c(0,1,2)
res <- local({ # just to keep all environments clean and to not re-assign `a`
a = as.numeric(as.character(a))
a[length(a) + 1] <- 5
a[ifelse(b == 0, which(a == 5), b)]
})
res
#[1] 5 1 2
a
#[1] 1 2 3 #not changed `a`
#Levels: 1 2 3
我想不出更优雅的方式来使用a[ifelse(, , )]
。另外,我不确定是否有任何限制。
我希望我没有错过任何严肃的事情。