Действительно ли ifelse вычисляет оба своих вектора каждый раз? Это медленно?
тут ifelse
реально вычислить yes
и no
векторы -- как в целом каждого вектора?
Или он просто вычисляет некоторые значения из каждого вектора?
и ifelse
действительно, что медленно?
1 ответ:
да. (За исключением)
ifelse
вычисляет оба своихyes
иno
значение. За исключением случая, когдаtest
условие-либо всеTRUE
илиFALSE
.мы можем увидеть это, генерируя случайные числа и наблюдая, сколько чисел на самом деле генерируется. (путем возврата
seed
).# TEST CONDITION, ALL TRUE set.seed(1) dump <- ifelse(rep(TRUE, 200), rnorm(200), rnorm(200)) next.random.number.after.all.true <- rnorm(1) # TEST CONDITION, ALL FALSE set.seed(1) dump <- ifelse(rep(FALSE, 200), rnorm(200), rnorm(200)) next.random.number.after.all.false <- rnorm(1) # TEST CONDITION, MIXED set.seed(1) dump <- ifelse(c(FALSE, rep(TRUE, 199)), rnorm(200), rnorm(200)) next.random.number.after.some.TRUE.some.FALSE <- rnorm(1) # RESET THE SEED, GENERATE SEVERAL RANDOM NUMBERS TO SEARCH FOR A MATCH set.seed(1) r.1000 <- rnorm(1000) cat("Quantity of random numbers generated during the `ifelse` statement when:", "\n\tAll True ", which(r.1000 == next.random.number.after.all.true) - 1, "\n\tAll False ", which(r.1000 == next.random.number.after.all.false) - 1, "\n\tMixed T/F ", which(r.1000 == next.random.number.after.some.TRUE.some.FALSE) - 1 )
дает следующий результат:
Quantity of random numbers generated during the `ifelse` statement when: All True 200 All False 200 Mixed T/F 400 <~~ Notice TWICE AS MANY numbers were generated when `test` had both T & F values present
мы также можем видеть это в самом исходном коде:
. . if (any(test[!nas])) ans[test & !nas] <- rep(yes, length.out = length(ans))[test & # <~~~~ This line and the one below !nas] if (any(!test[!nas])) ans[!test & !nas] <- rep(no, length.out = length(ans))[!test & # <~~~~ ... are the cluprits !nas] . .
обратите внимание, что
yes
иno
вычисляются только если есть некоторые неNA
стоимостьюtest
что этоTRUE
илиFALSE
(соответственно).
В этот момент-и это важная часть, когда речь заходит об эффективности -полнота каждого вектора вычисляется.
хорошо, но это медленнее?
давайте посмотрим, если мы можем проверить это:
library(microbenchmark) # Create some sample data N <- 1e4 set.seed(1) X <- sample(c(seq(100), rep(NA, 100)), N, TRUE) Y <- ifelse(is.na(X), rnorm(X), NA) # Y has reverse NA/not-NA setup than X
эти два утверждения приводят к одинаковым результатам
yesifelse <- quote(sort(ifelse(is.na(X), Y+17, X-17 ) )) noiflese <- quote(sort(c(Y[is.na(X)]+17, X[is.na(Y)]-17))) identical(eval(yesifelse), eval(noiflese)) # [1] TRUE
но один в два раза быстрее другого
microbenchmark(eval(yesifelse), eval(noiflese), times=50L) N = 1,000 Unit: milliseconds expr min lq median uq max neval eval(yesifelse) 2.286621 2.348590 2.411776 2.537604 10.05973 50 eval(noiflese) 1.088669 1.093864 1.122075 1.149558 61.23110 50 N = 10,000 Unit: milliseconds expr min lq median uq max neval eval(yesifelse) 30.32039 36.19569 38.50461 40.84996 98.77294 50 eval(noiflese) 12.70274 13.58295 14.38579 20.03587 21.68665 50