web-dev-qa-db-fra.com

Pourquoi les instructions ifelse de R ne peuvent-elles pas renvoyer des vecteurs?

J'ai trouvé les instructions ifelse de R de temps en temps assez pratiques. Par exemple:

ifelse(TRUE,1,2)
# [1] 1
ifelse(FALSE,1,2)
# [1] 2

Mais je suis quelque peu confus par le comportement suivant.

ifelse(TRUE,c(1,2),c(3,4))
# [1] 1
ifelse(FALSE,c(1,2),c(3,4))
# [1] 3

Est-ce un choix de conception supérieur à mon niveau de rémunération?

102
Christopher DuBois

La documentation de ifelse indique:

ifelse renvoie une valeur de la même forme que test qui est remplie d'éléments sélectionnés parmi yes ou no selon que l'élément de test est TRUE ou FALSE.

Puisque vous passez des valeurs de test de longueur 1, vous obtenez des résultats de longueur 1. Si vous passez des vecteurs de test plus longs, vous obtiendrez des résultats plus longs:

> ifelse(c(TRUE, FALSE), c(1, 2), c(3, 4))
[1] 1 4

Ainsi, ifelse est destiné à des fins spécifiques de test d'un vecteur de booléens et de retour d'un vecteur de même longueur, rempli d'éléments tirés du (vecteur) yes et no arguments.

C'est une confusion courante, à cause du nom de la fonction, de l'utiliser quand vraiment vous voulez juste une construction normale de if () {} else {} à la place.

83
Nathan Kitchen

Je parie que vous voulez une simple instruction if au lieu de ifelse - dans R, if n'est pas seulement une structure de flux de contrôle, elle peut renvoyer une valeur:

> if(TRUE) c(1,2) else c(3,4)
[1] 1 2
> if(FALSE) c(1,2) else c(3,4)
[1] 3 4
61
Ken Williams

Notez que vous pouvez contourner le problème si vous affectez le résultat à l'intérieur du 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
11
Cath

oui, je pense que ifelse () est vraiment conçu pour quand vous avez un grand vecteur de tests et que vous voulez mapper chacune à l'une des deux options. Par exemple, je fais souvent des couleurs pour plot () de cette façon:

plot(x,y, col = ifelse(x>2,  'red', 'blue'))

Si vous aviez un grand vecteur de tests mais que vous vouliez des paires pour les sorties, vous pourriez utiliser sapply() ou plyrllply() ou quelque chose, peut-être.

9
Brendan OConnor

Voici une approche similaire à celle suggérée par Cath, mais elle peut fonctionner avec des vecteurs pré-assignés existants

Il est basé sur l'utilisation de la get() comme ceci:

a <- c(1,2)
b <- c(3,4)
get(ifelse(TRUE, "a", "b"))
# [1] 1 2
4
bmonger

Parfois, l'utilisateur a juste besoin d'une instruction switch au lieu d'une ifelse. Dans ce cas:

condition <- TRUE
switch(2-condition, c(1, 2), c(3, 4))
#### [1] 1 2

(qui est une autre option de syntaxe de la réponse de Ken Williams)

3
agenis

utilisez `if`, par ex.

> `if`(T,1:3,2:4)
[1] 1 2 3
1
blueskyddd

Dans votre cas, en utilisant if_else de dplyr aurait été utile: if_else est plus strict que ifelse et génère une erreur pour votre cas:

library(dplyr)
if_else(TRUE,c(1,2),c(3,4))
#> `true` must be length 1 (length of `condition`), not 2
0
Matifou