Structures conditionnelles
La version originale de ce chapitre a été écrite par Ewen Gallic dans le cadre de son support de cours d’Ewen Gallic intitulé Logiciel R et programmation, chapitre 4 Boucles et calculs vectoriels
.
Il existe deux sortes de boucles dans R. Celles pour lesquelles les itérations continuent tant qu’une condition n’est pas invalidée (while
), et celles pour lesquelles le nombre d’itérations est défini au moment de lancer la boucle (for
).
Avant de présenter chacune de ces fonctions, il est nécessaire de préciser que les boucles ne sont pas le point fort de R. Dès que l’on souhaite appliquer une fonction à chaque élément d’un vecteur, et/ou que le résultat de chaque itération ne dépend pas de l’itération précédente, il est préférable de vectoriser les calculs (voir le chapitre sur la vectorisation).
Les boucles avec while
Quand on souhaite répéter un calcul tant qu’une condition est satisfaite, on utilise la fonction while
, avec la syntaxte suivante :
avec condition
une valeur logique (TRUE
ou FALSE
), et instruction
du code, qui peut être entouré d’accolades si on souhaite évaluer plusieurs instructions.
Le code instruction
sera répété tant que condition
est vrai. Prenons l’exemple d’une plante qui mesure 10 centimètres et qui va grandir de 10 % tous les ans jusqu’à atteindre 2 mètres.
taille <- 0.10
duree <- 0
while (taille < 2) {
taille <- taille * 1.1
duree <- duree + 1
}
message(glue::glue("La plante a atteint {round(taille, 1)} mètres en {duree} années."))
La plante a atteint 2.1 mètres en 32 années.
Les boucles avec for
Quand on connaît le nombre d’itérations à l’avance, on peut utiliser la boucle for
. La syntaxe est la suivante :
avec variable
le nom d’une variable locale à la boucle for
, vector
un vecteur à n
éléments définissant les valeurs que prendra variable pour chacun des n
tours, et instruction
le code à exécuter à chaque itération.
On peut utiliser for
pour remplir les éléments d’une liste, ou d’un vecteur.
[1] 1 2 3
À chaque itération, R doit trouver le vecteur de destination en mémoire, créer un nouveau vecteur qui permettra de contenir plus de données, copier données depuis l’ancien vecteur pour les insérer dans le nouveau, et enfin supprimer l’ancien vecteur (Ross, 2014). C’est une opération coûteuse en temps. Un moyen de rendre cette allocation plus efficace est de créer a priori le vecteur ou la liste en le remplissant avec des données manquantes. Ainsi, R n’aura pas besoin de ré-allouer la mémoire à chaque itération.
[1] 1 2 3
Les conditions
On peut soumettre l’exécution de codes en R à conditions que certaines conditions soient honorées.
Les instructions if … else
Les instructions if
et else
fournissent un moyen d’exécuter du code si une condition est respectée ou non. La syntaxe prend deux formes :
# Première forme (pas de code si condition == FALSE)
if (condition) {instruction si vrai}
# Seconde forme
if (condition) {instruction si vrai} else {instruction si faux}
avec condition
un logique, instruction si vrai
le code à exécuter si la condition est vérifiée et instruction si faux
le code à exécuter si la condition n’est pas remplie. À nouveau, on peut avoir recours aux accolades pour créer des regroupements.
[1] "Hello"
x <- 3
if (x == 2) print("Hello")
# Avec des instructions dans le cas contraire
if (x == 2) print("Hello") else print("x est différent de 2")
[1] "x est différent de 2"
[1] "La nouvelle valeur de x : 2"
Attention, lorsque l’on fait des regroupements et qu’on utilise la structure if
et else
, il est nécessaire d’écrire le mot else
sur la même ligne que la parenthèse fermante du groupe d’instructions à réaliser dans le cas où la condition du if
est vérifiée.
La fonction switch
Avec la fonction switch
, on peut indiquer à R d’exécuter un code en fonction du résultat obtenu lors d’un test. La syntaxe est la suivante :
avec valeur_test
un nombre ou une chaîne de caractères. Si valeur_test
vaut cas_1
, alors uniquement instruction_cas_1
sera évaluée, si valeur_test
vaut cas_2
, alors ce sera instruction_cas_2
qui le sera, et ainsi de suite. On peut rajouter une valeur par défaut en utilisant la syntaxte suivante :
switch(valeur_test,
cas_1 = {
instruction_cas_1
},
cas_2 = {
instruction_cas_2
},
...,
{
instruction_defaut
}
)
Voici un exemple d’utilisation, issu de la page d’aide de la fonction.
centre <- function(x, type) {
switch(type,
mean = mean(x),
median = median(x),
trimmed = mean(x, trim = .1)
)
}
x <- rcauchy(10)
centre(x, "mean")
[1] 1.79229
[1] 0.3857596
[1] 0.6393129
L’instruction repeat … break
L’instruction repeat
permet de répéter une expression. Il est nécessaire d’ajouter un test d’arrêt, à l’aide de l’instruction break
.
[1] 3
L’instruction next
L’instruction next
autorise de passer immédiatement à l’itération suivante d’une boucle for
, while
ou repeat
.
result <- rep(NA, 10)
for (i in 1:10) {
if (i == 5) next
result[i] <- i
}
# Le 5e élément de result n'a pas été traité
result
[1] 1 2 3 4 NA 6 7 8 9 10
Barre de progression
Lorsque l’exécution d’une boucle prend du temps, il peut être intéressant d’avoir une idée de l’état d’avancement des itérations. Pour cela, il est bien sûr possible d’afficher une valeur dans la console à chaque tour, chaque 10 tours, etc.
La fonction txtProgressBar
de l’extension utils
permet un affichage d’une barre de progression dans la console. Il suffit de lui fournir une valeur minimale et maximale, et de la mettre à jour à chaque itération. Le paramètre style autorise de surcroit à choisir un style
pour la barre. Le style numéro 3 affiche un pourcentage de progression, et est utile lorsque d’autres résultats sont affichés dans la console lors de l’exécution de la boucle, dans la mesure où la barre est de nouveau affichée au complet dans la console si nécessaire.
Dans l’exemple qui suit, à chacun des dix tours, une pause de 0.1 seconde est effectuée, puis la barre de progression est mise à jour.
nb_tours <- 10
pb <- txtProgressBar(min = 1, max = nb_tours, style = 3)
for (i in 1:nb_tours) {
Sys.sleep(0.1)
setTxtProgressBar(pb, i)
}
|
| | 0%
|
|====== | 11%
|
|=========== | 22%
|
|================= | 33%
|
|====================== | 44%
|
|============================ | 56%
|
|================================= | 67%
|
|======================================= | 78%
|
|============================================ | 89%
|
|==================================================| 100%
Pour plus d’options, on pourra se référer à la fonction progress_bar
de l’extension progress
, présentée en détail sur https://r-pkg.org/pkg/progress.
Si l’exécution est vraiment longue, et qu’on est impatient de connaître les résultats, il existe de plus une fonction amusante dans l’extension beepr
, qui porte le nom de beep
. Plusieurs sons peuvent être utilisés (voir la page d’aide de la fonction).
Pour approfondir
On pourra également consulter le chapitre Boucles et exécution conditionnelle de l’excellente Introduction à R et au tidyverse de Julien Barnier (https://juba.github.io/tidyverse).