Menu

If else en R : if, else if, ifelse() et switch()

La logique conditionnelle en R - syntaxe if/else if/else, le piège des accolades qui casse les scripts, ifelse() vectorisé pour des vecteurs entiers, et switch() pour les choix multiples.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

L'instruction if

Une instruction if en R exécute un bloc de code seulement quand une condition vaut TRUE. La condition va entre parenthèses, le code entre accolades, et un else facultatif fournit ce qui se passe sinon :

La condition score >= 60 s'évalue en un unique TRUE, donc la première branche s'exécute. Les opérateurs de comparaison et logiques - ==, >=, &&, %in% et compagnie - sont ce avec quoi tu construis ces conditions.

Pour plus de deux issues, enchaîne les tests avec else if. R parcourt la chaîne depuis la première condition et exécute la première branche dont la condition vaut TRUE, en sautant le reste :

L'ordre compte : comme 85 >= 80 est testé avant 85 >= 70, la note est "B". Si tu triais les tests dans l'autre sens, tout score au-dessus de 70 obtiendrait un "C".

Le piège des accolades : où doit aller le else

C'est l'erreur qui piège presque tout le monde au premier script R. Dans un script (ou tout ce qui est lancé avec Rscript), else doit apparaître sur la même ligne que l'accolade fermante de la branche précédente. Ceci échoue :

if (score >= 60) {
  print("You passed")
}
else {              # Error: unexpected 'else'
  print("Try again")
}

Pourquoi : R analyse instruction par instruction. Quand il atteint le } en début de ligne, l'instruction if est syntaxiquement complète, et R l'évalue sur-le-champ. Le else de la ligne suivante arrive alors comme le début d'une nouvelle instruction - et une instruction ne peut pas commencer par else. La correction est le motif utilisé partout dans cette page :

if (score >= 60) {
  print("You passed")
} else {            # brace and else on the same line
  print("Try again")
}

À l'intérieur d'un corps de fonction ou de tout autre jeu d'accolades englobant, la règle stricte se relâche (R continue de lire jusqu'à la fermeture de l'accolade extérieure), mais ne compte pas là-dessus - le style } else { marche partout et c'est ce que prescrivent les guides de style R.

La condition doit être un seul TRUE ou FALSE

if() exige exactement une valeur logique. Deux choses violent ça, et les deux sont des erreurs :

if (NA) print("hi")
# Error: missing value where TRUE/FALSE needed

if (c(TRUE, FALSE)) print("hi")
# Error: the condition has length > 1

Le cas NA compte en pratique parce que les comparaisons avec des données manquantes produisent des NA : si x vaut NA, alors x > 10 vaut NA, et un if nourri de cette condition arrête ton script. Le motif défensif utilise le court-circuit de && :

Comme !is.na(x) vaut FALSE, la partie x > 10 n'est jamais évaluée et aucun NA n'atteint la condition. La propagation des NA dans les comparaisons est traitée dans les valeurs manquantes.

L'erreur de longueur supérieure à 1 (appliquée depuis R 4.2 ; avant, R utilisait silencieusement le premier élément) signifie généralement que tu voulais plutôt : any(v > 5) si une seule correspondance suffit, all(v > 5) si chaque élément doit passer, ou ifelse() si tu voulais une réponse par élément - ce qui est la section suivante.

ifelse() : le if else vectorisé

if décide une fois. ifelse(test, yes, no) décide pour chaque élément d'un vecteur et renvoie un vecteur de même longueur :

Chaque élément de temps est testé indépendamment : "hot" "mild" "mild" "hot" "mild". C'est l'outil pour dériver un nouveau vecteur ou une nouvelle colonne de data frame à partir d'un existant - sans boucle.

Contrairement à if, ifelse() gère élégamment les valeurs manquantes : un NA dans le test produit un NA dans le résultat plutôt qu'une erreur :

Tu peux imbriquer des appels à ifelse() pour des découpages à trois voies, et à cette profondeur ça reste lisible :

Mais arrête-toi là. Trois appels ifelse() imbriqués ou plus deviennent un casse-tête d'appariement de parenthèses ; à ce stade, passe à cut() (pour des plages numériques) ou à dplyr::case_when(), qui pose chaque condition sur sa propre ligne.

switch() pour les choix multiples

Quand tu compares une valeur à une liste de noms connus - et non à des plages - une longue chaîne de else if est l'outil maladroit. switch() le dit directement :

Trois comportements à connaître :

  • Correspondance : switch() compare la valeur caractère aux noms des arguments et renvoie le résultat correspondant.
  • Basculement : un nom dont la partie droite est vide (sat = ,) bascule vers le résultat du cas suivant - c'est ainsi que "sat" et "sun" partagent "weekend" sans le répéter.
  • Valeur par défaut : le dernier argument sans nom ("weekday") est renvoyé quand rien ne correspond. Sans défaut, une valeur non appariée fait renvoyer NULL de façon invisible par switch() - ta fonction ne renvoie silencieusement rien, ce qui est un bug déroutant. Fournis toujours une valeur par défaut (ou fais-en un stop() explicite).

switch() brille dans les fonctions qui dispatchent sur un argument de mode ou de méthode ; pour tout ce qui repose sur des seuils numériques, reste sur else if ou cut().

Ce que tu retiens

  • if (condition) { } else { } - condition entre parenthèses, une branche s'exécute ; enchaîne avec else if, la première correspondance gagne.
  • Dans les scripts, écris } else { sur une seule ligne - un else en début de ligne est une erreur de syntaxe.
  • if() a besoin d'exactement un TRUE/FALSE : NA est une erreur, un vecteur plus long est une erreur (depuis R 4.2). Protège avec !is.na(x) &&, ou réduis avec any()/all().
  • ifelse(test, yes, no) est la version vectorisée - utilise-la pour calculer de nouveaux vecteurs, et ne l'imbrique pas plus de deux fois.
  • switch() gère le dispatch multiple sur des noms, avec basculement via les cas vides - donne-lui toujours une valeur par défaut.

Prochaine étape : faire quelque chose plus d'une fois - les boucles for, et quand une boucle est (ou n'est pas) le bon outil.

Questions fréquentes

Comment écrire une instruction if else en R ?

if (condition) { ... } else { ... } - la condition va entre parenthèses et chaque branche entre accolades. Enchaîne d'autres tests avec else if (condition). Dans un script, else doit se trouver sur la même ligne que l'accolade fermante de la branche précédente (} else {), sinon R signale unexpected 'else'.

Quelle est la différence entre if et ifelse() en R ?

if est une instruction de contrôle de flux qui teste exactement une valeur TRUE/FALSE et exécute une branche de code. ifelse(test, yes, no) est une fonction vectorisée : elle teste tous les éléments d'un vecteur d'un coup et renvoie un vecteur de résultats. Utilise if pour décider ce que fait ton programme ; utilise ifelse() pour calculer une nouvelle colonne ou un nouveau vecteur à partir d'un existant.

Pourquoi R dit-il « the condition has length > 1 » ?

Tu as passé un vecteur entier à if(), qui attend un seul TRUE ou FALSE. Depuis R 4.2, c'est une erreur plutôt qu'un usage silencieux du premier élément. Corrige en réduisant le vecteur à une valeur - any(x > 5), all(x > 5) - ou en passant au ifelse() vectorisé si tu voulais un résultat par élément.

Comment fonctionne switch() en R ?

switch(value, name1 = result1, name2 = result2, default) compare une valeur de type caractère aux noms des arguments et renvoie le résultat correspondant. Un nom dont la partie droite est vide bascule vers le résultat suivant, ce qui permet à plusieurs cas de partager une même issue. Le dernier argument sans nom joue le rôle de valeur par défaut ; sans lui, une valeur non appariée renvoie NULL de façon invisible.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER