Cours
Ce tutoriel sur les boucles en R passe en revue les constructions disponibles pour itérer, quand les utiliser, et comment recourir à des alternatives comme la vectorisation en R pour exécuter vos tâches d’itération plus efficacement.
Cet article présentera quelques exemples de boucles pour ensuite les critiquer et les déconseiller au profit des alternatives vectorisées les plus répandues parmi la riche collection de bibliothèques proposées par R.
De manière générale, le conseil de ce tutoriel serait : apprenez les boucles. Elles offrent une vision détaillée de ce qui se passe au niveau élémentaire et aident à comprendre les données que vous manipulez.
Et une fois que vous les maîtrisez, évitez-les.
Investissez plutôt dans l’apprentissage des alternatives vectorisées. Le gain d’efficacité en vaut la peine.
Pour vous entraîner de manière interactive, essayez le chapitre sur les boucles dans notre cours Intermediate R.
Qu’est-ce qu’une boucle ?
« Boucler », « itérer », « répéter » des instructions est une pratique ancienne, bien antérieure à l’invention de l’informatique. Il s’agit d’automatiser un processus en plusieurs étapes en organisant des séquences d’actions (des traitements par lots) et en regroupant les parties à répéter.
Tous les langages modernes proposent des constructions spéciales permettant de répéter des instructions ou des blocs d’instructions.
On distingue globalement deux types de ces constructions ou boucles. Certaines s’exécutent un nombre de fois prédéfini, contrôlé par un compteur ou un index incrémenté à chaque itération. Elles appartiennent à la famille des boucles for.
D’autres se basent sur l’évaluation d’une condition logique, testée au début ou à la fin de la boucle. Ces variantes appartiennent respectivement aux familles while ou repeat.
Introduction aux boucles en R
Selon le manuel de base de R, parmi les commandes de contrôle de flux, les constructions de boucle sont for, while et repeat, avec les clauses additionnelles break et next.
Rappel : les commandes de contrôle de flux permettent à un programme de bifurquer entre des alternatives, ou de « prendre des décisions ».
Vous pouvez à tout moment afficher ces commandes via ?Control dans la console RStudio.
?Control
Ce diagramme illustre les structures de boucle en R :

Les boucles for en R
Les sections suivantes détaillent chacune des structures de la figure ci-dessus. Nous commencerons par la structure de gauche, puis nous avancerons progressivement vers celles de droite.
Pour une introduction vidéo aux boucles for et un exercice, consultez le chapitre For Loop dans notre cours Intermediate R.
Explication des boucles for
Cette structure, composée du rectangle d’« init » (initialisation), du losange de décision et du rectangle i1, s’exécute un nombre connu de fois.
En termes de logigramme, les rectangles signifient « exécuter une action sans prise de décision ». Les losanges sont des « symboles de décision » : ils traduisent des questions à deux issues logiques possibles, Vrai (T) ou Faux (F).
Note : pour simplifier, d’autres symboles possibles sont omis dans la figure.
Une ou plusieurs instructions d’initialisation sont suivies de l’évaluation d’une condition sur une variable qui parcourt une séquence. Dans la figure, le losange représente : « la valeur courante de la variable v appartient‑elle à la séquence seq ? ».
Autrement dit, vous testez si la valeur courante de v se situe dans un intervalle spécifié. Vous définissez généralement cet intervalle dans l’initialisation, par exemple 1:100, pour démarrer la boucle.
Si la condition n’est pas satisfaite (résultat False), la boucle ne s’exécute pas. C’est indiqué par la flèche sortante à droite de la structure for. Le programme passe alors à la première instruction après le bloc.
Si la condition est vérifiée, on exécute l’instruction (ou le bloc) i1. Ce bloc peut lui-même contenir une autre boucle : on parle alors de boucle imbriquée.
Une fois terminé, on réévalue la condition. Les lignes reliant i1 au sommet du schéma (après l’initialisation) l’indiquent. En R – comme en Python – on peut l’exprimer en anglais courant : notre variable appartient‑elle à une plage de valeurs ?
Note : dans d’autres langages, par exemple en C, la condition s’écrit plus explicitement avec des opérateurs logiques (supérieur, inférieur, égal, …).
Voici un exemple simple de boucle for :
# Create a vector filled with random normal values
u1 <- rnorm(30)
print("This loop calculates the square of the first 10 elements of vector u1")
# Initialize `usq`
usq <- 0.
for (i in 1:10) {
# i-th element of `u1` squared into `i`-th position of `usq`
usq[i] <- u1[i] * u1[i]
print(usq[i])
}
print(i)
Le bloc for est délimité par des accolades. Elles peuvent être placées juste après la condition ou à la ligne suivante, avec indentation. Rien n’est strictement obligatoire, mais les accolades améliorent la lisibilité et facilitent le repérage du bloc de boucle et d’éventuelles erreurs.
Note : le vecteur des carrés, usq, est initialisé. Ce n’est pas nécessaire en R « pur », mais dans la version markup, knitr ne compilerait pas car la référence au vecteur précède sa création. Pour en savoir plus sur knitr, consultez la page R Markdown.
Imbriquer des boucles for
Maintenant que vous savez qu’on peut imbriquer des boucles for, vous vous demandez sans doute pourquoi et quand le faire.
Supposons que vous souhaitiez manipuler un tableau bidimensionnel en fixant des valeurs pour ses éléments.
Vous pourriez écrire :
# Insert your own integer here
my_int <- 42
nr <- as.integer(my_int)
# Create a `n` x `n` matrix with zeros
mymat <- matrix(0, nr, nr)
# For each row and for each column, assign values based on position
# These values are the product of two indexes
for (i in 1:dim(mymat)[1]) {
for (j in 1:dim(mymat)[2]) {
mymat[i, j] = i * j
}
}
Astuce : pour plus d’informations sur matrix(), consultez la documentation R.
i parcourt les lignes et j les colonnes.La fameuse table de multiplication, que vous connaissez par cœur.
Vous pouvez aussi choisir un entier et générer une table en fonction de votre choix : affectez un entier à une variable si la table est carrée, ou à deux variables si elle est rectangulaire. Cette variable servira alors de borne supérieure aux index i et j.
# Show the first 10x10 chunk or the first `nr` x `nr` chunk
if (nr > 10) {
mymat[1:10, 1:10]
} else
mymat[1:nr, 1:nr]
Note : pour éviter d’inonder l’écran avec d’immenses tableaux, on ajoute une condition finale qui n’affiche que le bloc 10 x 10 si l’entier demandé est supérieur à 10. Sinon, un bloc n x n est affiché.
Le code complet ressemble à ceci :
# Insert your own integer here
my_int <- 42
nr <- as.integer(my_int)
# Create a `n` x `n` matrix with zeroes
mymat <- matrix(0, nr, nr)
# For each row and for each column, assign values based on position
# These values are the product of two indexes
for (i in 1:dim(mymat)[1]) {
for (j in 1:dim(mymat)[2]) {
mymat[i, j] = i * j
}
}
# Show the first 10x10 chunk or the first `nr` x `nr` chunk
if (nr > 10) {
mymat[1:10, 1:10]
} else
mymat[1:nr, 1:nr]
Boucles for : populaires, mais pas toujours idéales
La boucle for est de loin la plus utilisée, et sa construction implique un nombre d’itérations fixé et connu à l’avance, comme dans « générer les 200 premiers nombres premiers » ou « lister les 10 clients les plus importants ».
Mais si vous ne connaissez pas le nombre d’itérations, ou que des conditions imprévisibles peuvent survenir ?
Par exemple, vous pourriez vouloir compter les clients vivant dans une zone identifiée par un code postal, ou le nombre de clics sur une bannière au cours des deux derniers jours, ou d’autres événements non anticipés.
Dans ces cas, la boucle while et sa cousine repeat peuvent vous sauver…
Boucles while
La boucle while, au centre de la figure, comporte un bloc d’initialisation suivi d’une condition logique. Cette condition est souvent l’évaluation d’une variable de contrôle par rapport à une valeur (supérieur, inférieur, égal), mais toute expression renvoyant Vrai ou Faux convient.
Si le résultat est Faux (F), la boucle ne s’exécute pas, comme l’indique la flèche sortante. Le programme passe à l’instruction suivant le bloc.
Si le résultat est Vrai (T), on exécute l’instruction (ou le bloc) i1.
Remarquez le bloc supplémentaire i2 : il met à jour la variable de contrôle, ce qui peut modifier le résultat de la condition au début de la boucle. Ce n’est pas obligatoire, mais courant (par exemple, incrémenter un compteur). Les itérations cessent lorsque la condition devient fausse.
La forme générale est while(cond) expr, où cond est la condition testée et expr l’expression à exécuter.
Par exemple, la boucle suivante demande à l’utilisateur via une fonction définie par l’utilisateur (UDF) d’entrer la « réponse à la grande question ». Elle recommence jusqu’à ce que l’utilisateur trouve la bonne réponse :
# Your User Defined Function
readinteger <- function(){
n <- readline(prompt="Please, enter your ANSWER: ")
}
response <- as.integer(readinteger())
while (response!=42) {
print("Sorry, the answer to whatever the question MUST be 42");
response <- as.integer(readinteger());
}
Pour commencer, utilisez une fonction utilisateur pour récupérer l’entrée avant d’entrer dans la boucle. Elle se poursuit tant que la réponse n’est pas 42.
Autrement, R se plaindrait d’une expression manquante pour fournir Vrai/Faux – il ne connaît pas encore « response » au moment d’entrer dans la boucle. Et si vous répondez juste d’emblée, la boucle ne s’exécutera pas du tout.
Boucles repeat
La boucle repeat, tout à droite du diagramme, est similaire à while, mais garantit l’exécution au moins une fois des blocs i1 et i2, quel que soit le résultat de la condition.
Dans d’autres langages, on parlerait de « repeat until » : exécuter jusqu’à ce que la condition devienne vraie (ou reste fausse), avec au moins une itération.
Variation de l’exemple précédent :
readinteger <- function(){
n <- readline(prompt="Please, enter your ANSWER: ")
}
repeat {
response <- as.integer(readinteger());
if (response == 42) {
print("Well done!");
break
} else print("Sorry, the answer to whatever the question MUST be 42");
}
Après la fonction d’entrée, le bloc repeat s’exécute au moins une fois et se termine dès que la condition de l’if est vérifiée.
Notez qu’il faut définir une condition de sortie via break. Cela nous amène à la notion d’interruption d’une boucle.
Interrompre et sortir d’une boucle en R
Comment sortir d’une boucle ?
Autrement dit, en dehors de la fin « naturelle » (nombre d’itérations atteint pour for, condition atteinte pour while ou repeat), peut-on interrompre une boucle ?
Oui, et comment ?
L’instruction break répond à la première question : vous l’avez vue dans l’exemple précédent.
Interrompre avec break
Quand l’interpréteur R rencontre break, il passe à l’instruction immédiatement après la boucle (s’il y en a une). Dans le cas de boucles imbriquées, break ne sort que de la boucle la plus interne.
Exemple :
Ce code définit une matrice m x n de zéros puis remplit ses cases via une double boucle for, mais seulement si les deux index diffèrent. L’objectif est de créer une matrice triangulaire inférieure : éléments sous la diagonale non nuls, le reste reste à zéro.
Quand les index sont égaux (condition sur j), un break interrompt la boucle interne et l’exécution reprend après celle-ci avec un print(). Puis on réévalue la condition de la boucle externe (i sur les lignes).
Si les index diffèrent, on assigne la valeur et on incrémente le compteur ctr. À la fin, on affiche ctr, le nombre d’assignations effectuées.
# Make a lower triangular matrix (zeroes in upper right corner)
m = 10
n = 10
# A counter to count the assignment
ctr = 0
# Create a 10 x 10 matrix with zeroes
mymat = matrix(0, m, n)
for (i in 1:m) {
for (j in 1:n) {
if (i == j) {
break
} else {
# you assign the values only when i<>j
mymat[i, j] = i * j
ctr = ctr + 1
}
}
print(i * j)
}
# Print how many matrix cells were assigned
print(ctr)
Note : il est parfois prudent d’utiliser des accolades même lorsqu’elles ne sont pas strictement nécessaires, pour garantir que tout { ouvert est bien refermé par un }. Un déséquilibre signale une erreur potentielle.
Utiliser next dans une boucle
next interrompt l’itération en cours et passe à la suivante. En pratique, on saute directement à la réévaluation de la condition de boucle.
Dans d’autres langages, l’équivalent s’appelle « continue » : au moment où la condition est vérifiée, passez à l’itération suivante.
Exemple simple :
m = 20
for (k in 1:m) {
if (!k %% 2)
next
print(k)
}
Ce code affiche tous les nombres impairs de 1:m (ici m=20). Les nombres dont le reste de la division par 2 est nul ne sont pas imprimés : le programme saute directement à l’évaluation de i in 1:m et ignore, ici, print(k).
En résumé : utiliser les boucles en R
- Mettez le moins de code possible dans la boucle en externalisant ce qui peut l’être. Tout ce qui est à l’intérieur sera répété de nombreuses fois, parfois inutilement.
- Attention avec
repeat: assurez-vous d’une condition d’arrêt explicite, sinon vous risquez la boucle infinie. - Si une boucle devient (trop) volumineuse, préférez des appels de fonctions à l’intérieur de la boucle. Cela rend le code plus clair. Mais l’usage de boucles imbriquées pour des opérations sur matrices/tableaux est souvent le signe qu’il existe mieux dans un langage orienté matrices comme R.
- Évitez de « faire grossir » une variable ou un jeu de données en réaffectant à chaque itération. Dans certains langages (comme Matlab), un avertissement est émis : vous pouvez continuer, mais mieux vaut envisager des alternatives. Un exemple typique suit dans la section suivante.
Quand utiliser des boucles en R
Très bien, mais quand faut‑il utiliser des boucles en R… et quand s’en passer ?
Dès qu’une ou plusieurs opérations doivent être répétées, une boucle peut être utile.
Vous devez simplement préciser combien de fois, ou sous quelles conditions, ces opérations s’exécutent : vous assignez des valeurs initiales à une variable de contrôle, vous lancez la boucle, puis vous exploitez les résultats.
Mais ne pourriez‑vous pas simplement dupliquer l’instruction souhaitée autant de fois ?
Règle empirique : si vous devez exécuter une action trois fois ou plus, une boucle vous servira mieux. Le code sera plus compact, lisible et maintenable, et vous taperez moins : si vous découvrez qu’une instruction doit se répéter une fois de plus, il suffit d’ajuster une variable dans la condition.
Cela dit, la nature de R invite à éviter les boucles dès qu’il existe des alternatives (!).
Bonne nouvelle : il en existe.
R possède une fonctionnalité rare : la vectorisation.
Quelles alternatives aux boucles en R ?
Qu’est‑ce que la vectorisation ?
Comme son nom l’indique, la vectorisation consiste à convertir des opérations répétées sur des nombres simples (« scalaires ») en opérations uniques sur des vecteurs ou des matrices. Vous en avez déjà vu des exemples ci‑dessus.
Un vecteur est la structure de données élémentaire en R, « une entité unique composée d’un ensemble d’éléments », selon le manuel de base.
Un ensemble de nombres constitue donc un vecteur numérique.
En combinant des vecteurs (de même longueur), vous obtenez une matrice. Vous pouvez le faire verticalement ou horizontalement avec différentes instructions R. Une matrice est donc un ensemble de vecteurs horizontaux ou verticaux. Par extension, on peut vectoriser des opérations répétées sur des vecteurs.
Beaucoup de constructions de boucle peuvent être rendues implicites via la vectorisation.
« Implicites » car elles ne disparaissent pas vraiment : au niveau inférieur, la forme vectorisée se traduit par du code contenant une ou plusieurs boucles dans le langage bas niveau utilisé (Fortran, C ou C++).
Elles sont invisibles pour l’utilisateur et généralement plus rapides que l’équivalent explicite en R ; à moins d’implémenter vos propres fonctions R dans ces langages, cela reste transparent pour vous.
Le cas le plus simple : additionner deux vecteurs v1 et v2 dans v3, élément par élément avec une boucle for :
v1 <- c(3,4,5)
v2 <- c(3,4,6)
v3 <- c(0,0,0)
n = length(v1)
for (i in 1:n) {
v3[i] <- v1[i] + v2[i]
}
v3
Ou en forme vectorisée « native » :
v3 = v1 + v2
v3
Note : on dit « native » car R sait que les opérateurs arithmétiques agissent sur des vecteurs et matrices.
De même, pour deux matrices A et B, au lieu d’additionner A[i,j] et B[i,j] élément par élément, avec deux index i et j, demandez à R :
A <- matrix(1:6, nrow = 3, ncol = 2)
B <- matrix(c(2,4,3,1,5,7), nrow=3, ncol=2)
C= A + B
C
Et c’est d’une simplicité déconcertante !
Pourquoi la vectorisation est‑elle plus rapide ?
Pourquoi la vectorisation est‑elle plus rapide alors que le nombre d’opérations élémentaires semble identique ?
Sans entrer trop dans les détails : R est un langage interprété. L’interpréteur gère pour vous les détails de définition des variables. Il le fait commande par commande, même si vous répétez la même instruction.
Un compilateur, lui, résout ces définitions à la compilation et produit un code binaire compact et optimisé. Or, de nombreuses fonctions R sont écrites dans ces langages bas niveau, d’où une meilleure efficacité.
En pratique, le code bas niveau fait appel à du C/C++, encapsulé dans un « wrapper ».
Ensuite, dans les langages qui supportent la vectorisation (R, Matlab), toute instruction opérant sur un nombre agit en réalité sur un objet nativement défini comme un vecteur, même d’un seul élément. Les définitions sont donc résolues une fois pour l’ensemble du vecteur, au lieu d’être répétées élément par élément dans une boucle : c’est plus rapide.
Enfin, manipuler des vecteurs natifs permet d’utiliser des routines d’algèbre linéaire très efficaces (BLAS). En exécutant des instructions vectorisées, R s’appuie sur ces bibliothèques. Le message à retenir : traitez des structures complètes en un seul appel de fonction autant que possible.
Passons à un exemple général de vectorisation, avant d’examiner des fonctions R populaires pour remplacer les boucles.
Exemple de vectorisation en R
Revenons à la notion de « faire grossir les données », une manière peu efficace de « mettre à jour » un data frame.
On crée d’abord une matrice m x n avec replicate(m, rnorm(n)) où m=10 vecteurs colonne de n=10 éléments sont générés par rnorm(n).
Puis on la transforme en data frame (10 observations de 10 variables) et on applique une opération algébrique à chaque élément via une double boucle for : à chaque itération, on ajoute une composante sinusoïdale.
L’exemple est artificiel, mais il peut représenter l’ajout d’un signal à un bruit aléatoire :
# This is a bad loop with 'growing' data
set.seed(42)
m = 10
n = 10
# Create matrix of normal random numbers
mymat <- replicate(m, rnorm(n))
# Transform into data frame
mydframe <- data.frame(mymat)
for (i in 1:m) {
for (j in 1:n) {
mydframe[i, j] <- mydframe[i, j] + 10 * sin(0.75 * pi)
print(mydframe)
}
}
Ici, la majeure partie du temps d’exécution est consacrée aux copies et à la gestion de la boucle.
Version vectorisée :
set.seed(42)
m = 10
n = 10
mymat <- replicate(m, rnorm(n))
mydframe <- data.frame(mymat)
mydframe <- mydframe + 10 * sin(0.75 * pi)
mydframe
C’est plus simple : la dernière ligne remplace la double boucle. Note l’usage de set.seed() pour obtenir exactement le même résultat.
Mesurons maintenant les temps d’exécution.
Utilisez des commandes système R, comme system.time(), à laquelle vous passez un bloc de code :
Astuce : placez le code à évaluer entre les parenthèses de system.time().
# Insert `system.time()` to measure loop execution
for (i in 1:m) {
for (j in 1:n) {
mydframe[i, j] <- mydframe[i, j] + 10 * sin(0.75 * pi)
}
}
# Add `system.time()` to measure vectorized execution
mydframe <- mydframe + 10 * sin(0.75 * pi)
Dans le code ci-dessus, vous choisissez m et n, créez la matrice et le data frame une seule fois, puis vous comparez le bloc for à la version « une ligne » via deux appels séparés à system.time().
Même avec m=n=10, la version vectorisée est environ 7 fois plus rapide, bien que l’écart reste peu visible à ce niveau.
Les différences deviennent sensibles à m=n=100. À 1000, la boucle for semble suspendue plusieurs dizaines de secondes, tandis que la version vectorisée s’exécute instantanément.
Pour m=n=10000, la boucle for dépasse la minute quand la version vectorisée prend environ 2,54 s. Ces mesures varient selon votre configuration, mais elles illustrent l’écart.
À noter : augmenter m et n impacte aussi fortement la génération de la matrice (testez avec system.time() autour de replicate).
N’hésitez pas à jouer sur m et n et à tracer le temps d’exécution en fonction du produit m x n : c’est l’indicateur pertinent car il exprime la taille des matrices, donc le nombre d’itérations nécessaires dans la boucle imbriquée.
Ceci n’est qu’un exemple de vectorisation. Il en existe bien d’autres. Dans R News (p. 46), vous trouverez des fonctions très efficaces pour calculer des sommes et moyennes par dimension : rowSums(), colSums(), rowMeans(), colMeans().
La newsletter mentionne également que « …les fonctions de la famille ‘apply’, nommées [s,l,m,t]apply, permettent d’appliquer une autre fonction aux éléments/dimensions d’objets. Elles offrent une syntaxe compacte pour des tâches parfois complexes, plus lisible et plus rapide que des boucles mal écrites. »
La famille apply : de simples boucles cachées ?
La famille très riche et puissante des fonctions apply est intrinsèquement vectorisée. Si, à première vue, on n’y voit pas de boucles, elles existent bel et bien sous le capot.
La commande apply (et sa famille [s,l,m,r,t,v]apply) appartient au package de base de R. Elle regroupe des fonctions pour manipuler de façon répétitive des « tranches » de matrices ou de tableaux, en traversant les données et en évitant des boucles explicites. On applique une fonction nommée à une matrice ou un tableau en entrée, avec des arguments optionnels.
Note : c’est pour cela qu’elles relèvent des « fonctionnelles » (voir la page Advanced R d’Hadley Wickham).
La fonction appelée peut être agrégative (une moyenne) ou de transformation/sous‑sélection.
Attention : ces fonctions ne sont pas nécessairement plus rapides ; l’intérêt majeur est d’éviter des boucles verbeuses, réduisant les risques d’erreur.
Les fonctions de la famille : apply(), sapply(), lapply(), mapply(), rapply(), tapply(), vapply().
Quand et comment les utiliser ?
Notez qu’un package comme plyr couvre ces fonctionnalités. Même si tout mémoriser sans documentation est difficile, ces fonctions constituent la base de combinaisons plus complexes.
Les trois plus utilisées :
apply()
Appliquer une fonction aux lignes (indice « 1 ») ou aux colonnes (indice « 2 ») d’une matrice. Voir cette page.
lapply()
Appliquer une fonction à chaque élément d’une liste et obtenir… une liste (le « l » de list). Voir la documentation.
sapply()
Appliquer une fonction à chaque élément d’une liste mais obtenir un vecteur plutôt qu’une liste. Plus d’infos sur cette page.
Des fonctions apparentées comme sweep(), by() et aggregate() sont parfois utilisées avec la famille apply().
Limitons‑nous ici à apply() (une discussion plus complète pourrait faire l’objet d’un autre article).
Étant donnée une matrice M, l’appel apply(M, 1, fun) ou apply(M, 2, fun) applique la fonction fun aux lignes (1) ou aux colonnes (2). Cet argument numérique s’appelle « margin » et vaut 1 ou 2 pour une matrice. Sur un tableau, on peut aller jusqu’à 8 dimensions.
La fonction peut être toute fonction R valide, y compris une fonction utilisateur (UDF) définie à l’intérieur de apply(), ce qui est très pratique.
apply() : exemple
# define matrix `mymat` by replicating the sequence `1:5` for `4` times and transforming into a matrix
mymat <- matrix(rep(seq(5), 4), ncol = 5)
# `mymat` sum on rows
apply(mymat, 1, sum)
# `mymat` sum on columns
apply(mymat, 2, sum)
# With user defined function within the apply that adds any number `y` to the sum of the row
# `y` is set at `4.5`
apply(mymat, 1, function(x, y)
sum(x) + y, y = 4.5)
# Or produce a summary column wise for each column
apply(mymat, 2, function(x, y)
summary(mymat))
Vous utilisez souvent des data frames : dans ce cas, assurez‑vous que les données sont du même type, sinon des conversions automatiques pourraient se produire, ce qui n’est probablement pas souhaité. Par exemple, dans un data frame mêlant texte et nombres, les valeurs numériques peuvent être converties en chaînes.
Dernières considérations sur l’usage des boucles et leurs alternatives en R
Nous sommes passés des constructions fondamentales de boucles à la notion (de base) de vectorisation, puis à un exemple d’utilisation d’une fonction de la famille apply(), très fréquente en R.
En matière de contrôle de flux, nous nous sommes limités aux boucles : for, while, repeat et aux façons de les interrompre/sortir.
Comme les dernières sections le suggèrent, il vaut souvent mieux éviter les boucles en R. Alors pourquoi les apprendre ?
À notre avis :
- Il est probable que R ne sera pas votre seul langage en data science. Maîtriser des constructions générales comme les boucles est une compétence précieuse. La syntaxe varie selon les langages, mais une fois acquises, vous les transposez facilement.
- L’écosystème R est immense et il est difficile, voire impossible, de connaître toutes les fonctions existantes. Il existe de multiples façons de faire, plus ou moins efficaces/élégantes, et votre apprentissage sera progressif. En pratiquant, vous chercherez des moyens plus efficaces et découvrirez des fonctions inconnues. Pendant que vous lisez ces lignes, de nouveaux packages sortent : tout connaître relève de l’illusion, sauf à être spécialiste R à plein temps.
- Enfin, tant qu’on ne traite pas des jeux de données très dimensionnels, une solution avec boucle peut être simple à coder et à lire. Comme data scientist, on peut vous demander un prototype ponctuel qui « fait le job ». L’élégance n’est pas toujours prioritaire. Dans le flux d’analyse, vous devez parfois surtout mobiliser votre expertise métier. La production sera prise en charge par un spécialiste back‑end (éventuellement dans un autre langage !).
Si, après ce tutoriel, les boucles for en R ne vous posent plus de difficulté, envisagez le cours Intermediate R de DataCamp. Il renforcera vos connaissances avec de nouveaux exercices. Si, en revanche, les boucles n’ont plus aucun secret pour vous, le cours Writing Functions in R, donné par Hadley et Charlotte Wickham, pourrait vous intéresser. Consultez aussi le tutoriel For Loops in R.
Exécutez et modifiez le code de ce tutoriel en ligne
Exécuter le codeFAQ sur les boucles en R
Qu’est-ce qu’une boucle en R et à quoi sert-elle ?
Les boucles permettent de répéter plusieurs fois un bloc de code. Elles sont utiles lorsque vous voulez appliquer la même action à plusieurs points de données ou objets, ou répéter une action jusqu’à ce qu’une condition soit remplie.
Quels sont les différents types de boucles en R ?
Il existe deux principaux types de boucles en R : les boucles for et les boucles while.
- Les boucles for répètent un bloc de code pour chaque élément d’une liste ou d’une séquence. Par exemple, vous pouvez utiliser une boucle for pour afficher tous les éléments d’un vecteur ou appliquer une fonction à chaque élément d’une liste.
- Les boucles while répètent un bloc de code tant qu’une condition est vraie. Par exemple, vous pouvez utiliser une boucle while pour continuer à demander une saisie utilisateur jusqu’à l’obtention d’une réponse valide.
Comment arrêter une boucle en R ?
Pour arrêter une boucle en R, vous pouvez utiliser l’instruction break. Elle interrompt immédiatement la boucle et l’exécution reprend après celle-ci.
Comment passer à l’itération suivante d’une boucle en R ?
Pour passer directement à l’itération suivante d’une boucle en R, utilisez l’instruction next. Elle ignore le reste de l’itération courante et enchaîne sur la suivante.
Puis-je mettre des boucles à l’intérieur d’autres boucles en R ?
Oui, vous pouvez imbriquer des boucles en R. On parle alors de « boucles imbriquées ». Par exemple, vous pouvez placer une boucle for dans une autre pour itérer sur les éléments d’une matrice.