2010-10-28 64 views
27
x = seq(0.1,10,0.1) 
y <- if (x < 5) 1 else 2 

我希望if能夠在每一種情況下運行,而不是在整個矢量上運行。 我必須改變什麼?R中的向量化IF語句?

+0

這也可能與'如果(條件){ } else(condition){}構造?如果沒有參數變得有點棘手,有時很難閱讀。我遇到了像基督教一樣的問題,如果其他問題仍然存在,就像這裏提到的那樣,這很好,但看起來很醜。到目前爲止,我正在使用表達式({是}),這是一個很好的解決方法,但我仍然想知道是否有一個用if和else來做。 – 2010-12-06 09:17:36

回答

42
x <- seq(0.1,10,0.1) 

> x 
    [1] 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1.0 1.1 1.2 1.3 1.4 1.5 
[16] 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 
[31] 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 4.0 4.1 4.2 4.3 4.4 4.5 
[46] 4.6 4.7 4.8 4.9 5.0 5.1 5.2 5.3 5.4 5.5 5.6 5.7 5.8 5.9 6.0 
[61] 6.1 6.2 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.2 7.3 7.4 7.5 
[76] 7.6 7.7 7.8 7.9 8.0 8.1 8.2 8.3 8.4 8.5 8.6 8.7 8.8 8.9 9.0 
[91] 9.1 9.2 9.3 9.4 9.5 9.6 9.7 9.8 9.9 10.0 

> ifelse(x < 5, 1, 2) 
    [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 
[38] 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 
[75] 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 
+2

這對於僅替換一些值也是非常有用的:例如'x = ...; x [x <5] = 1'是'ifelse(x <5,1,x)' – 2015-02-21 17:23:33

+0

如果我想返回另一個向量的元素,該怎麼辦? – skan 2017-03-08 13:38:53

+1

@skan嘗試'y [x <5]'。假設'x'和'y'的長度相同 – 2017-03-08 15:12:52

11

y <- if (x < 5) 1 else 2不會對整個向量(您收到警告告訴你只有條件的第一個元素將被使用)操作。你想ifelse

y <- ifelse(x < 5, 1, 2) 

ifelse運行在整個邏輯向量,元素的元素。 if只接受一個邏輯值。請參閱?"if"?ifelse

11

爲了完整:在大向量中,可以使用索引來加快速度(我們通常在模擬中執行此操作,其中函數通常運行1000到10000次)。但只要沒有必要,只需使用ifelse即可。這讀起來更容易。

> set.seed(100) 
> x <- runif(1000,1,10) 

> system.time(replicate(10000,{ 
+  y <- ifelse(x < 5,1,2) 
+ })) 
    user system elapsed 
    2.56 0.08 2.64 

> system.time(replicate(10000,{ 
+ y <- rep(2,length(x)) 
+ y[x < 5]<- 1 
+ })) 
    user system elapsed 
    0.48 0.00 0.48 
+3

您可以進一步縮短這個時間。我的機器在0.436中執行了第二種方法(儘管它在第一種方法中速度較慢),但是這又使其再提高了200%:system.time(replicate(10000,{ 2010-10-31 04:31:10

+0

@Dwin:非常好的解決方案!謝謝。但是在我的機器上,它的運行速度只有微小的提高(0.47比0.48) – 2010-10-31 19:59:35

+5

小心 - 如果'x'包含'NA'元素(在第一個元素中保留「NA」,但將被賦值爲1 '第二個)。 – jbaums 2014-07-13 09:31:59

0

繼上述文章之後,您甚至可以使用和修改滿足標準的矢量元素。在我看來,如果計算速度更快並不昂貴,那麼應該始終這樣做。

x = seq(0.1,10,0.1) 
y <- rep(2,length(x)) 
y[x<5] <- x[x<5]*2 

上一篇文章的代碼最好回答這個問題。但是,如果我不得不使用上面的代碼,我會做:

x = seq(0.1,10,0.1) 
y <- rep(2,length(x)) 
y[x<5] <- x[x<5]*0 +1 
+0

答案可能會根據投票向上或向下移動,因此與「上述帖子」相關可能會很麻煩。 – 2016-08-31 17:40:39

1

你也可以只創建邏輯向量和1把它

x <- seq(0.1, 10, 0.1) # Your data set 
(x >= 5) + 1 
# [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 
# [92] 2 2 2 2 2 2 2 2 2 

如果想比較性能,將是最快的解決方案

set.seed(100) 
x <- runif(1e6, 1, 10) 

RL <- function(x) y <- ifelse(x < 5,1,2) 
JM <- function(x) {y <- rep(2, length(x)); y[x < 5] <- 1} 
DA <- function(x) y <- (x >= 5) + 1 

library(microbenchmark) 
microbenchmark(RL(x), 
       JM(x), 
       DA(x)) 

# Unit: milliseconds 
# expr  min  lq  mean median  uq  max neval 
# RL(x) 331.83448 366.52940 378.89182 374.99741 381.08659 609.21218 100 
# JM(x) 38.72894 42.18745 44.36493 43.25086 44.09626 82.76168 100 
# DA(x) 10.01644 11.96482 14.21593 13.17825 14.12930 53.76923 100 
+0

對於更有效率的方法,您可以將代碼修改爲'function(x)y <- (x > = 5L)+ 1L',但通常是一個很好的答案,並且有趣的是看看'ifelse'的速度有多慢。 – 2014-12-30 14:21:09

0
nzMean <- function(x) { mean(x[x!=-1],na.rm=TRUE)} 

nzMin <- function(x) {min(x[x!=-1],na.rm=TRUE)} 

nzMax <- function(x) { max(x[x!=-1],na.rm=TRUE)} 

nzRange<-function(x) {nzMax(x)-nzMin(x)} 

nzSD <- function(x) { SD(x[x!=-1],na.rm=TRUE)} 

#following function works 
nzN1<- function(x) {ifelse(x!=-1,(x-nzMin(x))/nzRange(x) ,x) } 

#following is bad as it returns only 4 not 5 elements of vector 
nzN2<- function(x) {ifelse(x!=-1,(x[x!=-1]-nzMin(x))/nzRange(x) ,x) } 

#following is bad as it returns 5 elements of vector but not correct answer 
nzN3<- function(x) {ifelse(x!=-1,(x[x!=-1]-nzMin(x))/nzRange(x) ,-1) } 

y<-c(1,-1,-20,2,4) 
a<-nzMean(y) 
b<-nzMin(y) 
c<-nzMax(y) 
d<-nzRange(y) 
# test the working function 
z<-nzN1(y) 

print(z)