In primo luogo, ifelse
fa NON valutare sempre le due espressioni - solo se ci sono entrambi TRUE
e FALSE
elementi nel vettore di prova.
ifelse(TRUE, 'foo', stop('bar')) # "foo"
E a mio parere:
ifelse
dovrebbe non essere utilizzato in una situazione di non-vectorized. È sempre più lento e più soggetto a errori utilizzare ifelse
oltre 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)
In situazioni vectorized però, ifelse
può essere una buona scelta - ma attenzione che la lunghezza e gli attributi del risultato potrebbe non essere quello che ti aspetti (come sopra, e considero ifelse
rotto in tal senso).
Ecco un esempio: tst
è di lunghezza 5 e ha una classe. Mi aspetto che il risultato sia di lunghezza 10 e non abbia classe, ma non è quello che succede: ottiene una classe incompatibile e una lunghezza 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"
Perché mi aspetto che la lunghezza sia 10? Poiché la maggior parte le funzioni in "ciclo" R il vettore più breve per abbinare i più lunghi:
1:5 + 1:10 # returns a vector of length 10.
... Ma ifelse
solo cicli i sì/nessun argomento in base alla lunghezza dell'argomento tst.
Perché dovrei aspettarmi che la classe (e altri attributi) a non venga copiata dall'oggetto di prova? Perché <
che restituisce un vettore logico non copia classe e attributi dai suoi argomenti (in genere numerici). Non lo fa perché in genere sarebbe molto sbagliato.
1:5 < structure(1:10, class='mynum') # returns a logical vector without class
Infine, può essere più efficiente "fai da te"?Bene, sembra che ifelse
non sia un primitivo come if
e che abbia bisogno di un codice speciale per gestire NA
. Se non hai NA
s, può essere più veloce farlo da solo.
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
grazie! Non ho tempo di guardarlo ora, ma lo farò più tardi stasera. Grazie per i tuoi commenti ed esempi. –
ottimi consigli ed esempi. Grazie! –
Si noti che 'ifelse' esegue il riciclo vettoriale - se una delle variabili' yes' o 'no' non ha una lunghezza uguale a' test', otterrà il riciclo. Ciò significa che il codice di prova alla fine dell'esempio produrrà risultati identici solo se tutti i vettori hanno la stessa lunghezza. Prova ad esempio questo dato di input: 'tst <- sample (c (TRUE, FALSE), 1e2, replace = TRUE); a <- 1: 100; b <- - (1:50); ' – Andrie