¿Ifelse realmente calcula ambos vectores cada vez? ¿Es lento?

¿Realmente ifelse calcula los vectores yes y no , como en, la totalidad de cada vector? ¿O solo calcula algunos valores de cada vector?

Además, ¿es realmente tan lento?

Sí. (Con excepción)

ifelse calcula tanto su valor yes como su valor no . Excepto en el caso en que la condición de test sea TRUE o FALSE .

Podemos ver esto generando números aleatorios y observando cuántos números realmente se generan. (invirtiendo la 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 ) 

Da el siguiente resultado:

 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 

También podemos verlo en el código fuente en sí:

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

Observe que yes y no se computan solo si hay algún valor de test no NA que sea TRUE o FALSE (respectivamente).
En ese punto, y esta es la parte importante en lo que respecta a la eficiencia, se computa la totalidad de cada vector .


Ok, pero ¿es más lento?

Veamos si podemos probarlo:

 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 

Estas dos declaraciones generan los mismos resultados

 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 

pero uno es dos veces más rápido que el otro

 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 
Intereting Posts