Créer des boucles


Lors de l'exemple avec la fonction 'intégrale' dans le chapitre sur les définitions de fonctions, la résolution du problème a nécessité que la fonction s'appelle plusieurs fois elle-même de manière récursive en faisant varier ses paramètres. Une autre approche serait de répéter plusieurs fois l'opération de calcul des petites surfaces en changeant à chaque calcul les coordonnées de la base: de x = a à x = a + d, puis de x = a + d à x = a + 2*d, etc.


I. La boucle for


Une structure de R permet de faire facilement ce genre d'opérations: la structure 'for':

for (liste) { instructions }

La liste prend souvent la forme 'i in valeurs' où 'valeurs' est une série de valeurs que la variable 'i' va prendre successivement. Voici un exemple:

somme<-0
for(i in 1:10){somme<-somme+i}
somme
## [1] 55

Une utilisation fréquente des boucles est de remplir un vecteur. Supposons qu'on cherche à obtenir les moyennes de 1000 échantillons de taille 20 extraits d'une distribution normale de moyenne 100 et de déviation standard 10. Le code suivant effectue cette opération:


m<-vector("numeric",1000)
for (i in 1:1000) {m[i]<-mean(rnorm(20,mean=100,sd=10))}
var(m)
## [1] 5.256445

La dernière instruction calcule la variance des 1000 moyennes générées aléatoirement et, comme on s'y attendait, obtient un résultat qui est à peu près 20 fois plus petit que la variance des données de départ (qui valait 10^2 = 100). Si vous ne comprenez pas pourquoi la variance des moyennes est si faible, relisez votre cours de stat...


On peut également utiliser les boucles pour calculer l'intégrale de la manière suivante:

integrale<-function(f,a,b,delta){
  surface<-0
  n<-ceiling((b-a)/delta)+1
  liste<-seq(a,b,length.out = n)
  for(i in 1:(n-1)){
    surface<-surface+delta/2*(f(liste[i])+f(liste[i+1]))
}
surface}

L'interprétation de ce code est la suivante: la deuxieme ligne initialise la variable 'surface' à 0. La troisième ligne calcule le nombre d'éléments de la liste des valeurs pour lesquelles on calculera la fonction: il s'agit du nombre d'intervalles (déterminé en fonction des limites d'intégration 'a' et 'b' et de la taille des intervalles 'delta'). La fonction 'ceiling' fournit l'arrondi supérieur. Elle permet d'avoir des intervalles d'une largeur inférieure ou égale à celle qui est spécifiée: par exemple, si 'a = 0', 'b = 2' et 'delta = 0.4', l'expression 'n<-ceiling((b-a)/delta)+1' conduit à 'n = ceiling(2/0.4)+1 = 6' signifiant qu'il y a 6 valeurs de x pour lesquelles on calculera f(x), soit 0.0, 0.4, 0.8, 1.2, 1.6 et 2.0. Si 'delta = 0.3', on obtient 'n = ceiling(2/0.3)+1 = 8'. La liste est ensuite générée en ligne 4 grâce à la fonction 'seq'. La boucle 'for' est utilisée pour cumuler les petits éléments de surface. La dernière instruction effectuée dans la fonction est celle figurant à la ligne 8, la valeur retournée par la fonction est la surface recherchée. On peut tester ce code en tapant:


x2<-function(x){x**2}
integrale(x2,2,3,0.001)
## [1] 6.333333

Cette valeur correspond bien à l'intégrale recherchée, soit x³/3 entre 2 et 3, ou encore, 27/3 - 8/3 = 19/3 = 6.333.


II. La boucle repeat


Lorsque le nombre de parcours de la boucle n'est pas connu à priori, il est souvent plus commode d'employer la structure 'repeat', qui sera executée jusq'à ce qu'une instruction 'break' fasse quitter la boucle. Voici un exemple de l'utilisation de cette instruction:


somme<-0 ; compteur<-0
repeat{
  if(somme+compteur>1000){
    print(compteur)
    break
  }
  else{
    somme<-somme+compteur
    compteur<-compteur+1
  }
}
## [1] 45

Ce code montre que 45 est le premier nombre pour lequel la somme 1+2+3+...+45 est supérieure à 1000.
Voici un autre exemple:


integrale<-function(f,a,b,delta){
  surface<-0
  x<-a
  repeat{
    if ((x+delta)>b){
      surface<-surface+(b-x)/2*(f(x)+f(b))
      break
    }
    else{
      surface<-surface+delta/2*(f(x)+f(x+delta))
      x<-x+delta
    }
  }
surface}


III. La boucle while


La boucle while offre des possibilités assez similaires aux deux précédentes: elle permet de faire effectuer des boucles si une condition est respectée. La syntaxe est la suivante:

while (condition) expression

On peut à nouveau illustrer l'utilisation de cette structure de controle sur l'exemple de l'intégrale:

integrale<-function(f,a,b,delta){
  surface<-0
  x<-a
  while (x<b){
    if ((x+delta)>b){
      surface<-surface+(b-x)/2*(f(x)+f(b))
      x<-b
    }
    else{
      surface<-surface+delta/2*(f(x)+f(x+delta))
      x<-x+delta
    }
  }
surface}