[英]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.