什么是解决a [b]可能返回不同长度向量的问题的有效方法?

时间:2013-11-04 11:38:59

标签: r

> 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的结果因回收而损坏。

我可以用ifelseif...else,但效率很低。处理它的常用方法是什么?

4 个答案:

答案 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(, , )]。另外,我不确定是否有任何限制。

我希望我没有错过任何严肃的事情。