Chapitre 5 tests conditionnels, boucles et fonctions Programmation en R
Introduction # Comme tout langage de programmation, R permet de programmer des test conditionnels et des boucles, ainsi que de définir ses propres fonctions. # Nous allons aborder les éléments suivants: # - tests conditionnels if-else # - boucles for # - boucles while # - boucles repeat # - création de fonctions
Tests conditionnels « if-else » # La syntaxe d'un test conditionnel est la suivante: #if (condition){ # instructions 1... #} else{ # instructions 2... #} # Un test conditionnel se comprend de la manière suivante: # Si "condition" est vraie, alors "instuctions 1" sont exécutées; sinon, ce sont "instructions 2" qui sont exécutées. # La clause "else" est facultative. # L'accolade fermante du "if" et le "else" doivent être sur la même ligne.
Tests conditionnels « if-else » # on génère un nombre aléatoire à partir d'une loi uniforme x <- runif(1, 0, 10) if (x > 5){ print("le nombre tiré est plus grand que 5") } else{ print("le nombre tiré est plus petit ou égal à que 5") } [1] "le nombre tiré est plus grand que 5"
Tests conditionnels « if-else » # Si on désire multiplier les conditions, on peut rajouter des "else if (condition)..." à volonté. x <- runif(1, 0, 10) if (x > 5){ print("le nombre tiré est plus grand que 5") } else if (x < 5) { print("le nombre tiré est plus petit que 5") } else { print("le nombre vaut 5") } [1] "le nombre tiré est plus petit que 5"
Boucles « for » # Les boucles "for" sont les plus importantes. # La syntaxe d'une boucle "for" est la suivante: # for (variable in structure_de_données){ # instructions... #} # Une boucle "for" se comprend de la manière suivante: # pour "variable" prenant successivement toutes les valeurs de "structure_de_données", exécuter les "instructions"... # L'élément "structure_de_données" peut être un vecteur, une liste, une matrice, un tableau, un data frame, etc. # Les instructions "next" et "break" permettent de sauter une itération ou d'intrrompre la boucle, respectivement.
Boucles « for » # Lorsque la structure de données parcourue est un vecteur ou une liste, la variable de la boucle "for" la parcourt dans le sens évident. # En général, la boucle "for" s'utilise sur un vecteur généré par la fonction seq(). for (i in seq(from=5, to=25, by=5)){ print(i) } [1] 5 [1] 10 [1] 15 [1] 20 [1] 25
Boucles « for » # La structure de données n'a pas besoin d'être numérique. s <- c("a", "b", "c") for (x in s){ print(x) } [1] "a” [1] "b” [1] "c"
Boucles « for » # Lorsque la structure de données parcourue est une matrice, la variable de la boucle "for" la parcourt ligne par ligne. X <- matrix(c(1,1,1,2,2,2), 2, 3) # 2 lignes, 3 colonnes for (i in X){ print(i) } [1] 1 [1] 2
Boucles « for » # Lorsque la structure de données parcourue est un data frame, la variable de la boucle "for" la parcourt colonne par colonne. D <- data.frame(col1 = c("a", "b", "c"), col2 = c(1, 2, 3), col3 = c(T, F, T)) for (v in D){ print(v) } [1] a b c Levels: a b c [1] 1 2 3 [1] TRUE FALSE TRUE
Boucles « for » # On peut bien évidemment faire des boucles imbriquées. # la fonction seq_len renvoie la taille d'une séquence. x <- matrix(1:6, 2, 3) for(i in seq_len(nrow(x))) { for(j in seq_len(ncol(x))) { print(x[i, j]) } [1] 1 [1] 3 [1] 5 [1] 2 [1] 4 [1] 6
Boucles « while » # La syntaxe d'une boucle "while" est la suivante: # while (condition){ # instructions... #} # Une boucle "while" se comprend de la manière suivante: # tant que "condition" est vraie, exécuter les "instructions"...
Boucles « while » count <- 0 while (count < 5){ print(count) count <- count + 1 # incrémente count } [1] 0 [1] 1 [1] 2 [1] 3 [1] 4
Boucles « while » # On simule une marche aléatoire z <- 5 z_walk <- c() while (z >= 3 && z <= 10){ coin <- rbinom(1, 1, 0.5) # flip a fair coin if (coin == 1){ z <- z + 1 z_walk <- append(z_walk, "Right") } else { z <- z - 1 z_walk <- append(z_walk, "Left") } print(z_walk) [1] "Right" "Right" "Right" "Right" "Right" "Left" ...
Boucles « repeat » # La syntaxe d'une boucle "repeat" est la suivante: # repeat { # instructions... #} # Une boucle "repeat" se comprend de la manière suivante: # répéter à l'infini les "instructions"... # Ainsi, puisqu'il faut bien que la boucle se stoppe, il faudra forcément inclure une instruction break dans les "instructions".
Boucles « repeat » # On génère des jets de pièces jusqu'à ce qu'une séquence de 5 piles ou 5 faces de suite soit générée. # Ça peut être long... (ou ne jamais arriver?) h <- c() # vecteur qui enrégistrera l'histoire de la pièce # On flip une "fair coin" 5 fois pour commencer for (i in seq(1,5,1)){ h <- append(h, rbinom(1, 1, 0.5)) } # On continue à flipper des "fair coins" jusqu'à ce qu'une séquence de 5 piles ou 5 faces de suite soit générée.
Boucles « repeat » repeat { # on selectionne les 5 derniers éléments de history h_tail <- h[seq(length(h)-4,length(h),1)] # si ce sont cinq 0's ou cinq 1's, on "break" la boucle # h_tail == 0 ou h_tail == 1 génère un # vecteur booléen de taille 5 # s'il se somme à 1, c'est que tous les éléments # valent 0 ou 1 if (sum(h_tail == 1) == 5 | (sum(h_tail == 0) == 5)) { break } else { # on reflip la "fair coin" et ajoute le résultat # à history h <- append(h, rbinom(1, 1, 0.5)) }
Boucles « repeat » print(h) [1] 1 0 1 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 [22] 1 1 0 1 0 1 1 0 0 1 1 0 0 0 0 0 # on a bien terminé avec un séquence de 5 faces de suite.
Fonctions # Comme pour tout langage de programmation, en R, il est possible et utile de définir ses propres fonctions. # Pour définir une fonction, on utilise le mot-clé "function". # La syntaxe de la définition d'une fonction est la suivante: # nom_fonction <- function(arguments) instructions... # ou alors, sur plusieurs lignes: # nom_fonction <- function(arguments){ # instructions... # } # Si l'on désire que la fonction retourne explicitement un résultat, on utilise la fonction return().
Fonctions # On reprogramme l'addition. f1 <- function(x, y) x + y f1(2,7) [1] 9 # Une fonction qui calcule le volume d'une sphère. volume_sphere <- function(rayon) { return((4/3)*pi*rayon^3) # avec return } volume_sphere(3) [1] 113.0973
Fonctions # On définit une fonction "norm" qui calcule la norme d'un vecteur de taille quelconque. norm <- function(v) { sqrt(sum(v^2)) } norm(c(3, 4)) # = sqrt(3^2 + 4^2) [1] 5 norm(c(1, 7, -3)) [1] 7.681146 norm(c(22, -7, 4, 5, -14)) [1] 27.74887
Fonctions # Comme souvent, les variables définies à l'intérieur d'une fonction sont locales! # Elles n'écrasent pas les variables du même nom définie à l'extérieur de la fonction, dites globales. v <- c("a", "b", "c") # variable globale f2 <- function(a, b){ v <- c(1, 2, 3) # variable locale return(a*v + b) } f2(5,8) [1] 13 18 23 v [1] "a" "b" "c" # la variable globale v a gardé sa valeur (globale).
Fonctions # On peut assigner des valeurs par défaut aux arguments, auquel cas ils deviennent optionnels; la syntaxe est: # arg = val_par_défaut. # Fonction qui calclule la combinaison linéaire a*x + b (a, b réels et x vecteur). comb_lin <- function(a = 1, x = c(1), b = 1){ a * x + b } comb_lin(3, c(1, 2, 3), 5) [1] 8 11 14 comb_lin(c(1, 2, 3)) # a et b valent 1 par défaut [1] 2 3 4 # Si on les nomme, on peut donner les arguments dans le mauvais ordre. comb_lin(x = c(1, 2, 3), a = 3) # b vaut 1 par défaut [1] 4 7 10
Fonctions # Il est utile de pouvoir créer des fonctions qui prennent un nombre variable d'arguments. On utilise la fameuse syntaxe "...". # la fonction summary fournit un résumé des statistiques de base d'un échantillon. v <- sqrt(1:100) # initialisation d'un échantillon resume <- function(message,...){ print(message) summary(...) # tous les argument "..." sont passés # dans summary }
Fonctions resume("Résumé de votre échantillon", v, digits = 3) # Dans ce cas, tout ce qui vient après le premier argument, à savoir "v, digits = 3" est compris comme "..." et passé à la fonction summary. [1] "Résumé de votre échantillon" Min. 1st Qu. Median Mean 3rd Qu. Max. 1.00 5.07 7.11 6.71 8.67 10.00
Exemple # On programme une fonction qui cherche le point fixe d'une autre fonction, s'il existe. # On utilise l'algorithme de point fixe classique: # x_0 = point de départ # x_N = f(x_N-1) pout n = 1,2,3,... # Répéter l'étape jusqu'à ce que |x_n - x_n-1| < epsilon. # Si la fonction n'a pas de point fixe, l'algorithme ne va pas converger.
point_fixe <- function(f, x_0, nb_it = 1000, epsilon = 1e-10){ x_N <- x_0 # variable locale iteration <- 1 # variable locale repeat{ erreur <- abs(x_N - f(x_N)) # variable locale if (erreur < epsilon) { # on retourne le résultat resultat <- c(x_N, f(x_N), iteration) break } else if (iteration > nb_it){ # pas de résultat print("Pas de convergence...") resultat <- c("NaN", iteration) } else { # on continue les itérations iteration <- iteration + 1 x_N <- f(x_N) return(resultat)
Exemple # On cherche un point fixe de la fonction cosinus à partir de x_0 = 0.3 point_fixe(cos, 0.3) [1] 0.7390851 0.7390851 58.0000000