Por que as declarações de Ifelse de R não podem devolver vetores?
-
20-09-2019 - |
Pergunta
Eu achei as declarações Ifelse de R muito úteis de tempos em tempos. Por exemplo:
ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2
Mas estou um pouco confuso com o seguinte comportamento.
ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3
Esta é uma opção de design acima do meu paygrade?
Solução
A documentação para ifelse
estados:
ifelse
retorna um valor com a mesma forma quetest
que é preenchido com elementos selecionados de qualqueryes
ouno
dependendo se o elemento detest
éTRUE
ouFALSE
.
Como você está passando pelos valores de teste do comprimento 1, você está obtendo resultados do comprimento 1. Se você passar por vetores de teste mais longos, obterá resultados mais longos:
> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4
Então ifelse
destina -se ao objetivo específico de testar um vetor de booleanos e devolver um vetor do mesmo comprimento, preenchido com elementos retirados do (vetor) yes
e no
argumentos.
É uma confusão comum, por causa do nome da função, para usá -lo quando você realmente quer apenas um normal if () {} else {}
construção em vez disso.
Outras dicas
Aposto que você quer um simples if
declaração em vez de ifelse
- em R, if
Não é apenas uma estrutura de fluxo de controle, ele pode retornar um valor:
> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4
Observe que você pode contornar o problema se atribuir o resultado dentro do ifelse
:
ifelse(TRUE, a <- c(1,2), a <- c(3,4))
a
# [1] 1 2
ifelse(FALSE, a <- c(1,2), a <- c(3,4))
a
# [1] 3 4
Sim, acho que o ifelse () foi realmente projetado para quando você tem um grande vetor longo de testes e deseja mapear cada um de duas opções. Por exemplo, geralmente faço cores para plot () dessa maneira:
plot(x,y, col = ifelse(x>2, 'red', 'blue'))
Se você tivesse um grande vetor longo de testes, mas queria pares para saídas, você poderia usar sapply()
ou plyr
's llply()
Ou algo assim, talvez.
Aqui está uma abordagem semelhante à sugerida por Cath, mas pode funcionar com os vetores pré-atribuídos existentes
É baseado em usar o get()
igual a:
a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2
Às vezes o usuário só precisa de um switch
declaração em vez de um ifelse
. Nesse caso:
condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2
(que é outra opção de sintaxe da resposta de Ken Williams)
Use `if`, por exemplo
> `if`(T,1:3,2:4)
[1] 1 2 3
No seu caso, usando if_else
a partir de dplyr
teria sido útil: if_else
é mais rigoroso do que ifelse
, e lança um erro para o seu caso:
library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2