簡體   English   中英

比ifelse更有效的比較數字的方法?

[英]More efficient way to compare numbers than ifelse?

考慮簡單數據:

    > cbind(x,y)
           x  y
    [1,]  -1 99
    [2,]   5  4
    [3,]  10 -2
    [4,] 600  0
    [5,] -16  1
    [6,]   0 55

現在考慮這個簡單的嵌套ifelse語句:

ifelse(y>=0, ifelse(x<0,y,ifelse(x>y,y,x)), x)

這給了我一個結果:

[1] 99  4 10  0  1  0

應該很容易看出代碼的作用:它用x替換x中的值:

1)如果x,y都是非負的,則y中的值越小

2)如果x為負,則y的任何非負值

或者單獨留下x。

我的問題是:這段代碼的計算效率不是很高,你能想出任何有效編碼的方法嗎? 謝謝!

你可以使用x是和, y(x+y)/2(xy)/2 然后用邏輯表達式計算( TRUE等於1, FALSE等於0):

(x+y + (1+2*((x<=y)*(x>=0)-(y>=0)))*(x-y))/2

給出與嵌套ifelse相同的結果。 速度比較,使用長度為500的向量:

> set.seed(1)

> x <- sample(-100:100,500,replace=TRUE)

> y <- sample(-100:100,500,replace=TRUE)

> system.time(
+   for ( i in 1:100000 )
+   {
+     A <- (x+y + (1+2*((x<=y)*(x>=0)-(y>=0)))*(x-y))/2
+   }
+ )
   user  system elapsed 
   8.46    0.00    8.51 

> system.time(
+   for ( i in 1:100000 )
+   {
+     B <- ifelse(y>=0, ifelse(x<0,y,ifelse(x>y,y,x)), x)
+   }
+ )
   user  system elapsed 
  74.58    0.03   75.05 

> system.time(
+   for ( i in 1:100000 )
+   {
+     z <- y
+     z[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0];z
+   }
+ )
   user  system elapsed 
  23.32    0.00   23.44 

檢查結果是否相同:

> all(A==B)
[1] TRUE
> all(A==z)
[1] TRUE
> 

沒有索引的另一個選項:

x * ((x < y & x >= 0) | y < 0) + y * ((x > y & y >= 0) | x < 0) 

輸出:

[1] 99  4 10  0  1  0

時間比較,似乎mra68答案是最快的:

library(microbenchmark)
microbenchmark(
  TylerRinker = z[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0],
  mra68 =(x+y + (1+2*((x<=y)*(x>=0)-(y>=0)))*(x-y))/2,
  mpalanco = x *((x < y & x >= 0)| y < 0)+ y * ((x > y & y >= 0)| x < 0),
  if_else = ifelse(y>=0, ifelse(x<0,y,ifelse(x>y,y,x)), x)
  ) 

   Unit: microseconds
        expr    min      lq     mean median     uq     max neval cld
 TylerRinker  8.800  9.7780 11.47480 10.267 10.268  75.778   100  a 
       mra68  5.867  6.3560  9.40188  6.845  7.334 214.623   100  a 
    mpalanco  7.334  7.8230  8.67836  8.311  8.800  30.312   100  a 
     if_else 44.489 45.9565 54.61929 53.289 53.290 245.911   100   b

也許只是索引。 我不知道它是否更有效率:

dat <- read.table(text="       x  y
    [1,]  -1 99
    [2,]   5  4
    [3,]  10 -2
    [4,] 600  0
    [5,] -16  1
    [6,]   0 55", header=TRUE)



x <- dat[, 1]
y <- dat[, 2]

z <- y
z[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0];z

## 99  4 10  0  1  0

這是對上述答案的總結,而不是一個獨特的答案; 但我確實提供時間比較。

通過組合操作, b是一個小的加速。 ce都是以前提供的答案。 @ mra68的答案看起來最快

library(microbenchmark)
microbenchmark(a= ifelse(y>=0, ifelse(x<0,y,ifelse(x>y,y,x)), x),
               b= {ifelse(y>= 0, ifelse(x>y | x<0, y,x), x)},
               c= {z <- y; z[(x < y & x >= 0)| y < 0] <- x[(x < y & x >= 0)| y < 0];z},
               d= x * ((x < y & x >= 0) | y < 0) + y * ((x > y & y >= 0) | x < 0),
               e= (x+y + (1+2*((x<=y)*(x>=0)-(y>=0)))*(x-y))/2)

Unit: microseconds
 expr    min      lq     mean median     uq    max neval cld
    a 16.346 18.6270 21.88066 19.387 20.528 77.548   100   c
    b 10.644 11.4040 13.05781 11.785 12.545 39.154   100  b 
    c  3.801  4.1820  5.10146  4.562  4.942 18.247   100 a  
    d  3.041  3.4210  4.37168  3.801  3.802 33.452   100 a  
    e  2.281  2.8515  3.36810  3.041  3.421 18.246   100 a  

雖然,IMO,在最快的解決方案中缺乏可讀性並不值得加速。

根據實際使用情況,您可以通過訂購if-else操作來實現加速,以便最小數量的操作在調用堆棧中向下傳遞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM