Dans cette section du cours, nous verrons deux sortes de structures de contrôle. Nous verrons comment contrôler notre code avec des conditions et des boucles.
vec_boo<-c(T,F,T,T,F,T)
Convertissons ce vecteur en valeurs numériques
as.numeric(vec_boo)
On peut faire des tests logiques afin de comparer deux ou plusieurs valeurs.
Pour ce faire, cérons un vecteur vec
vec<-1:10
Regardons si le premier élément est inférieur à 5 par exemple;
vec[1]<5
Est-ce que le 6e élément est inférieur à 5?
vec[6]<5
vec[5]>=5
On peut extraire de ce vecteur les valeurs supérieures à 6 par exemple;
vec[vec>6]
vec[vec>=6]
vec[!(vec>=6)]
Les valeurs plus petites ou égales à 3 ou
plus grandes ou égales à 6
vec[(vec>=8)|(vec<=3)]
Mais pourquoi on fait ça? On vient de voir qu'il n'est pas toujours nécessaire d'utiliser des if
. Je tiens à vous montrer qu'il est préférable d'éviter les if
lorsque possible, cela améliore grandement le temps d'exécution.
Toutefois, dans d'autres situations, par exemple lorsqu'on veut afficher un caractère quelconque lorsqu'une condition donnée est respectée. Regardons un exemple;
if(vec[1]>3){print("cet élément est plus grand que 3")} else {print("cet élément n'est pas plus grand que 3")}
Exemple d'un if
impriqué
age<-30
if(age>18 && age<=35){cat_age<-"jeune"}else {cat_age<-"trop_vieux_ou_trop_jeun"}
cat_age
age<-18
if(age>18 && age<=35){cat_age<-"jeune"}else if (age>35 && age<=55){cat_age<-"jeune"} else {cat_age<-"trop_vieux_ou_trop_jeun"}
cat_age
Regardons une version vectorisée de ces conditions
Ville_1<-"Montréal"
if(Ville_1=='Montréal'){
Province_1<-"Québec"
} else {
Province_1<-"autre"
}
Province_1
Maintenant si l'on assigne Toronto à Ville_1, on obtient;
Ville_1<-"Toronto"
if(Ville_1=='Montréal'){
Province_1<-"Québec"
} else {
Province_1<-"autre"
}
Province_1
Ajoutons une autre condition;
Ville_1<-"Toronto"
if(Ville_1=='Montréal'){
Province_1<-"Québec"
} else if (Ville_1=='Toronto'){
Province_1<-"Ontario" }else {Province_1<-"autre"}
Province_1
Ville_1<-"Montréal"
if(Ville_1=='Montréal'){
Province_1<-"Québec"
} else if (Ville_1=='Toronto'){
Province_1<-"Ontario" }else {Province_1<-"autre"}
Province_1
Il est très conseillé de toujours vectoriser lorsqu'on travaille avec R
.
Ville<-c("Montréal","Vancover","Toronto")
province<-ifelse(Ville=="Toronto","Ontario",ifelse(Ville=="Montréal","Québec","autre"))
province
L'expression ifelse
est la suivante: ifelse(<condition>,<expressionSiVrai>,<expressionSiFaux>)
Ville<-c("Montréal","Laval","Brossard")
province<-ifelse(Ville=="Toronto","Ontario",ifelse(Ville=="Montréal","Québec","autre"))
province
Lors de l'utilisation de l'instruction if()
, il est préférable a:
- d'utiliser
all.equal(x,y)
plutôt quex == y
- d'utiliser
!all.equal(x,y)
plutôt quex != y
Voici un exemple;
x<-.2-.1
y<-.3-.2
x==y
Pourtant on sait que c'est vrai! La fonction all.equal
permet de régler ce problème, car elle contient un paramètre de tolérance de précision.
all.equal(x,y)
for (i in 1:5){
print(paste("le chiffre:", i, "dans la boucle"))
}
À chacune des itérations, on peut insérer un nombre illimité de codes qu'on voudrait exécuter (plusieurs lignes de codes et non qu'une seule ligne). Par exemple, à chaque itération on calcule le carré de l'élément d'un vecteur.
for (i in 1:5){
i_carr<-i**2
print(paste("le chiffre:", i, "dans la boucle et son carré est:", i_carr))
}
On peut aussi inclure des conditions if
for (i in 1:5){
i_carr<-i**2
print(paste("le chiffre:", i, "dans la boucle et son carré est:", i_carr))
if (i==5)
{print("fin de la boucle")}
}
next
L'instruction next
permet d'amener le curseur d'exécution du programme au départ de la boucle. On donne alors l'ordre au programme de sauter cette étape et de passer à la suivante. Dans l'exemple suivant, on ordonne au programme de passer à l'étape suivante si la valeur de l’élément courant dans la boucle est égale à 2.
for (i in 1:5){
if (i==2){next}
print(paste("le chiffre:", i, "dans la boucle"))
}
for (i in 1:5){
if (i==4){break}
print(paste("le chiffre:", i, "dans la boucle"))
}
i=0
while (i<5){
i<-i+1
print(paste("le chiffre:", i, "dans la boucle"))
}
Dans ce genre de boucle, il arrive que le code continue de s'exécuter jusqu'à ce qu'on force l'arrêt. Par exemple le code suivant:
# i=1
# while (i<5){
# print(paste(i, Sys.time()))
# }
On aurait pu éviter cette boucle infinie en ajoutant l'instruction break
. Par exemple, sortir de la boucle s'il s'écoule 3 secondes entre le passage sur le premier élément et l'élément courant.
i=1
t_0<-Sys.time()
while (i<2){
if((Sys.time()-t_0)>3){break}
print(paste(i, Sys.time()))
}
n=1
repeat{
n<-n+1
print(mean(rnorm(100)))
if (n>=7) {break}
}
append
Nous avons appris à faire des boucles, mais comment peut-on garder en mémoire ou dans un objet l'information obtenue de chaque itération? Par exemple, à chaque itération, nous désirons faire un calcul et conserver le résultat. Regardons un exemple ou l'on voudrait calculer la moyenne de 100 variables aléatoires générées selon une distribution normale centrée réduite. On voudrait alors conserver le résultat (la moyenne calculée dans ce cas) qui a été calculé à chaque itération.
Nous créons un objet vide au départ, qu'on appelle moyennes
(au pluriel), et dans lequel nous insérons la moyenne calculée à chaque itération.
moyennes<-NULL
for (i in 1:1000){
mu<-mean(rnorm(100))
moyennes<-rbind(moyennes, mu)
}
plot(moyennes)
Toutefois, cette manière n'est pas la plus optimale en termes de temps de calcul. pour le prouver, utilisons la fonction system.time()
afin de mesurer le temps d'exécution de la boucle précédente, mais cette fois sur 20000 valeurs.
moyennes<-NULL
a<-system.time(
for (i in 1:20000){
mu<-mean(rnorm(100))
moyennes<-rbind(moyennes, mu)
}
)
a
moyennes<-numeric(length = 20000)
b<-system.time(
for (i in 1:20000){
mu<-mean(rnorm(100))
moyennes[i] <-mu
}
)
b
Ce qu'on vient de faire est génial! au lieu d'ajouter le résultat calculé à l'objet vide à chaque itération, nous assignons plutôt le résultat à l'index courant du vecteur vide.
Comparons les temps écoulés entre les deux manières de faire:
round(a[3]/b[3],2)
Donc la première façon de faire et 9.32 fois plus lente que la deuxième!