En primer lugar, hace ifelse
NO siempre evalúan ambas expresiones - sólo si hay dos TRUE
y FALSE
elementos en el vector de prueba.
ifelse(TRUE, 'foo', stop('bar')) # "foo"
Y en mi opinión:
ifelse
debe no usarse en una situación de no vectorizado. Es siempre más lenta y más propenso a errores utilizar ifelse
sobre if
/else
:
# This is fairly common if/else code
if (length(letters) > 0) letters else LETTERS
# But this "equivalent" code will yield a very different result - TRY IT!
ifelse(length(letters) > 0, letters, LETTERS)
En situaciones vectorizados embargo, ifelse
puede ser una buena opción - pero ten en cuenta que la longitud y los atributos del resultado podría no sea lo que esperas (como arriba, y considero que ifelse
está roto en ese sentido).
Aquí está un ejemplo: tst
es de longitud 5 y tiene una clase. Esperaría que el resultado fuera de longitud 10 y no tuviera clase, pero eso no es lo que sucede: ¡tiene una clase incompatible y longitud 5!
# a logical vector of class 'mybool'
tst <- structure(1:5 %%2 > 0, class='mybool')
# produces a numeric vector of class 'mybool'!
ifelse(tst, 101:110, 201:210)
#[1] 101 202 103 204 105
#attr(,"class")
#[1] "mybool"
¿Por qué esperar que la longitud sea 10? Debido a que la mayoría de las funciones de "ciclo" R el vector más corto para que coincida con los más largos:
1:5 + 1:10 # returns a vector of length 10.
... Pero sólo ifelse
ciclos de los sí/no hay argumentos para que coincida con la longitud del argumento TST.
¿Por qué esperaría que se copiara la clase (y otros atributos) a no del objeto de prueba? Porque <
que devuelve un vector lógico no copia la clase y los atributos de sus argumentos (típicamente numéricos). No hace eso porque normalmente estaría muy mal.
1:5 < structure(1:10, class='mynum') # returns a logical vector without class
Por último, ¿puede ser más eficiente "hacerlo usted mismo"?Bueno, parece que ifelse
no es una primitiva como if
, y necesita algún código especial para manejar NA
. Si no tiene NA
s, puede ser más rápido hacerlo usted mismo.
tst <- 1:1e7 %%2 == 0
a <- rep(1, 1e7)
b <- rep(2, 1e7)
system.time(r1 <- ifelse(tst, a, b)) # 2.58 sec
# If we know that a and b are of the same length as tst, and that
# tst doesn't have NAs, then we can do like this:
system.time({ r2 <- b; r2[tst] <- a[tst]; r2 }) # 0.46 secs
identical(r1, r2) # TRUE
gracias! No tengo tiempo para analizar esto ahora, pero lo haré más tarde esta noche. Gracias por sus comentarios y ejemplos. –
excelentes consejos y ejemplos. ¡Gracias! –
Tenga en cuenta que 'ifelse' sí realiza el reciclaje de vectores: si cualquiera de las variables' yes' o 'no' tienen una longitud desigual a' test', se reciclarán. Esto significa que su código de prueba al final de su ejemplo solo arrojará resultados idénticos si todos los vectores tienen la misma longitud. Pruebe, por ejemplo, estos datos de entrada: 'tst <- sample (c (TRUE, FALSE), 1e2, replace = TRUE); a <- 1: 100; b <- - (1:50); ' – Andrie