Contributeurs et contributrices au développement de cet atelier
en modifiant et en améliorant son contenu dans le cadre du
Learning and Development Award du CSBQ:
2022 - 2021 - 2020
Pedro Henrique P. Braga
Gabriel Muñoz
Parnian Pourtaherian
Kate Sheridan
2019 - 2018 - 2017
Katherine Hébert
Pedro Henrique P. Braga
Gabriel Muñoz
Marie-Hélène Brice
2016 - 2015 - 2014
Johanna Bradie
Sylvain Christin
Zofia Taranu
Ben Haller
Pedro Henrique P. Braga
Sebastien Portalier
Jacob Ziegler
Zofia Taranu
Cédric Frenette Dussault
Pour suivre cet atelier, vous devez avoir téléchargé et installé la dernière version des logiciels RStudio et R.
Tout le matériel pour cet atelier se retrouve au r.qcbs.ca/fr/workshops/r-workshop-05/.
R
R
utiles
Souvenez-vous de l'atelier n°1 ?
num.vector <- c(1, 4, 3, 9, 32, -4) num.vector# [1] 1 4 3 9 32 -4
char_vector <- c("bleu", "rouge", "vert")char_vector# [1] "bleu" "rouge" "vert"
bool_vector <- c(TRUE, TRUE, FALSE) # ou c(T, T, F)bool_vector# [1] TRUE TRUE FALSE
Nous pouvons commencer par créer des vecteurs multiples (petit rappel : Atelier n°1) :
siteID <- c("A1.01", "A1.02", "B1.01", "B1.02") soil_pH <- c(5.6, 7.3, 4.1, 6.0) num.sp <- c(17, 23, 15, 7) treatment <- c("Fert", "Fert", "No_fert", "No_fert")
Nous les combinons ensuite en utilisant la fonction data.frame()
.
my.first.df <- data.frame(siteID, soil_pH, num.sp, treatment)
my.first.df# siteID soil_pH num.sp treatment# 1 A1.01 5.6 17 Fert# 2 A1.02 7.3 23 Fert# 3 B1.01 4.1 15 No_fert# 4 B1.02 6.0 7 No_fert
Nous pouvons également créer des listes en combinant les vecteurs que nous avons créés auparavant.
my.first.list <- list(siteID, soil_pH, num.sp, treatment)
my.first.list# [[1]]# [1] "A1.01" "A1.02" "B1.01" "B1.02"# # [[2]]# [1] 5.6 7.3 4.1 6.0# # [[3]]# [1] 17 23 15 7# # [[4]]# [1] "Fert" "Fert" "No_fert" "No_fert"
En programmation, le contrôle de flux (en anglais, control flow) est simplement l'ordre dans lequel le programme est exécuté.
Tout ceci augmente la productivité!
On peut utiliser des organigrammes pour planifier et représenter la structure des programmes.
Les deux composantes de base de programmation sont:
Exécuter des commandes conditionnellement en utilisant:
if() {}if() {} else {}
Répéter l'exécution d'une commande en boucle tant qu'une condition n'est pas satisfaite.
for() {}while() {}repeat {}
Les clauses de sélection et d'itéraction peuvent également être contrôlées par des procedures de terminaison et de saut :
breaknext
les clauses if
et if
else
la boucle for
les clauses break
et next
la boucle repeat
la boucle while
Cette feuille de route apparaît au début de chaque outil de flux de contrôle pour faire savoir aux participants ce qui se passe dans la section flux de contrôle.
Condition if()
if(condition) { expression}
Commande if
else
if(condition) { expression 1} else { expression 2}
if()
et if()
else
testent une seule condition;ifelse()
pour:a <- 1:10ifelse(test = a > 5, yes = "oui", no = "non")# [1] "non" "non" "non" "non"# [5] "non" "oui" "oui" "oui"# [9] "oui" "oui"
a <- (-4):5sqrt(ifelse(test = a >= 0, yes = a, no = NA) )# [1] NA NA# [3] NA NA# [5] 0.000000 1.000000# [7] 1.414214 1.732051# [9] 2.000000 2.236068
if()
else
nichéesAlors que les instructions if()
et if()
else
vous laissent exactement deux options, l'instruction imbriquée if()
else
vous permet d'envisager d'autres alternatives:
if (test_expression1) {Procedure 1} else if (test_expression2) {Procedure 2} else if (test_expression3) {Procedure 3} else {Procedure 4}
R
!Que pensez-vous qu'il arrivera si nous essayons le code ci-dessous ?
if(2+2) == 4 print("Ouf, tout va bien!")else print("C'est la fin du monde!")
R
!Que pensez-vous qu'il arrivera si nous essayons le code ci-dessous ?
if(2+2) == 4 print("Ouf, tout va bien!")else print("C'est la fin du monde!")
# Error: <text>:1:9: unexpected '=='# 1: if(2+2) ==# ^
Cela ne fonctionne pas parce que R
évalue la première ligne et ne sait pas que vous allez utiliser else
.
Utilisez les parenthèses bouclées {}
afin que R
sache qu'il faut s'attendre à plus de commandes. Essayez :
if(2+2 == 4) { print("Ouf, tout va bien!")} else { print("C'est la fin du monde!")} # [1] "Ouf, tout va bien!"
Considérez les objets suivants :
Minou <- "chat"Pitou <- "chien"Filou <- "chat"animaux <- c(Minou, Pitou, Filou)
if()
pour afficher “meow”
si Minou
est un “chat”
.if()
else
pour afficher “woof”
si un objet a la valeur “chien”
, et “meow”
si non. Essayez ceci sur les objets Pitou
et Filou
.ifelse
pour afficher “woof”
pour les animaux
qui sont des chiens et “meow”
pour les animaux
qui sont des chats.if()
pour afficher “meow”
si Minou
est un “chat”
.if(Minou == 'chat') { print("meow")}# [1] "meow"
2.Utilisez une commande if
else
pour afficher “woof”
si un objet a la valeur “chien”
, et “meow”
si non. Essayez ceci sur les objets Pitou
et Filou
.
x = Minou# x = Pitouif(x == 'chat') { print("meow")} else { print("woof")}# [1] "meow"
3. Utilisez la fonction ifelse()
pour afficher “woof”
pour les animaux
qui sont des chiens et “meow”
pour les animaux
qui sont des chats.
animaux <- c(Minou, Pitou, Filou)ifelse(animaux == 'chien', "woof", "meow")# [1] "meow" "woof" "meow"
Ou
for(val in 1:3) { if(animaux[val] == "chat") { print("meow") }else if(animaux[val] == "chien") { print("woof") }else print("quoi?")}# [1] "meow"# [1] "woof"# [1] "meow"
Opérateur | Signification |
---|---|
== |
égal à |
!= |
pas égal à |
< |
plus petit que |
<= |
plus petit que ou égal à |
> |
plus grand que |
>= |
plus grand que ou égal à |
x&y |
x ET y |
x |y |
x OU y |
isTRUE(x) |
est-ce que X est vrai? |
Une boucle permet de répéter une ou plusieurs opérations.
Les boucles sont utiles pour:
les clauses if
et if
else
la boucle for
les clauses break
et next
la boucle repeat
la boucle while
for()
Une boucle for()
exécute un nombre fixe d'itérations:
for(i in séquence) { expression }
for()
La lettre i
peut être remplacée par n'importe quelle nom de variable, ou même une liste de vecteurs.
# Essayez les commandes ci-dessous et observez les résultats:for (a in c("Bonjour", "programmeurs", "en R")) { print(a)}for (z in 1:30) { a <- rnorm(n = 1, mean = 5, sd = 2) print(a)}elements <- list(1:3, 4:10)for (element in elements) { print(element)}
for()
Dans l'exemple générique ci-dessous, R
exécuterait l'expression 5 fois, chacune d'elles en remplaçant séquentiellement i
par des nombres de 1 à 5 :
for(i in 1:5) { expression}
L'expression
peut être n'importe quoi :
print(i + 1)
vector.a[i] <- 1 + i
matrix.b[i, 1] <- matrix.a[i, 1] * 2
for()
Dans l'exemple générique ci-dessous, R
exécuterait l'expression 5 fois, chacune d'elles en remplaçant séquentiellement i
par des nombres de 1 à 5 :
for(i in 1:5) { expression}
L'expression
peut être n'importe quoi :
print(i + 1)
vector.a[i] <- 1 + i
matrix.b[i, 1] <- matrix.a[i, 1] * 2
Dans cet exemple, chaque instance de m
est remplacé par chaque chiffre entre 1
et 7
, jusqu'au dernier élément de la séquence:
for(m in 1:7) { print(m*2)}
# [1] 2# [1] 4# [1] 6# [1] 8# [1] 10# [1] 12# [1] 14
for()
Nous allons effectuer des opérations pour les éléments pairs à l'intérieur de x
en utilisant l'opérateur modulo (%%
) :
x <- c(2, 5, 3, 9, 6)count <- 0
for(val in x) { if(val %% 2 == 0) { count <- count + 1 }}print(count)
for()
Les boucles for()
sont souvent utilisées pour exécuter des opérations successivement sur un jeu de données. Nous utiliserons des boucles pour exécuter des fonctions sur le jeu de données CO2
, qui est intégré dans R.
data(CO2) # This loads the built in datasetfor(i in 1:length(CO2[,1])) { # for each row in the CO2 dataset print(CO2$conc[i]) # print the CO2 concentration}
for()
Les boucles for()
sont souvent utilisées pour exécuter des opérations successivement sur un jeu de données. Nous utiliserons des boucles pour exécuter des fonctions sur le jeu de données CO2
, qui est intégré dans R.
data(CO2) # This loads the built in datasetfor(i in 1:length(CO2[,1])) { # for each row in the CO2 dataset print(CO2$conc[i]) # print the CO2 concentration}
Les 40 premiers résultats :
# [1] 95# [1] 175# [1] 250# [1] 350# [1] 500# [1] 675# [1] 1000# [1] 95# [1] 175# [1] 250
# [1] 350# [1] 500# [1] 675# [1] 1000# [1] 95# [1] 175# [1] 250# [1] 350# [1] 500# [1] 675
# [1] 1000# [1] 95# [1] 175# [1] 250# [1] 350# [1] 500# [1] 675# [1] 1000# [1] 95# [1] 175
# [1] 250# [1] 350# [1] 500# [1] 675# [1] 1000# [1] 95# [1] 175# [1] 250# [1] 350# [1] 500
for()
Truc 1. Pour exécuter une boucle sur chaque ligne d'un jeu de donnée, on utilise la fonction nrow()
for (i in 1:nrow(CO2)) { # pour chaque ligne du jeu de données CO2 print(CO2$conc[i]) # affiche les concentrations de CO2}
Truc 2. On peut aussi itérer des opérations sur les éléments d'une colonne.
for (p in CO2$conc) { # pour chacune des valeurs de concentration de CO2 print(p) # afficher cette valeur}
for()
L'expression dans la boucle peut peut contenir plusieurs lignes de commandes différentes.
for (i in 4:5) { # pour i de 4 à 5 print(colnames(CO2)[i]) print(mean(CO2[,i])) # affiche les moyennes de cette colonne}
Sortie:
# [1] "conc"# [1] 435# [1] "uptake"# [1] 27.2131
for()
nichéesDans certains cas, des boucles nichées peuvent être utiles pour accomplir une tâche. Dans ce cas, il est important d'utiliser un nom de variable d'itération différent pour chaque boucle. Ici, on utilise i
et n
:
for (i in 1:3) { for (n in 1:3) { print (i*n) }}
# Sortie# [1] 1# [1] 2# [1] 3# [1] 2# [1] 4# [1] 6# [1] 3# [1] 6# [1] 9
apply()
La famille de fonctions apply()
consistent de fonctions vectorisées qui permettent d'éviter de créer des boucles de façon explicite.
apply()
applique des fonctions sur une matrice.
(hauteur <- matrix(c(1:10, 21:30), nrow = 5, ncol = 4))# [,1] [,2] [,3] [,4]# [1,] 1 6 21 26# [2,] 2 7 22 27# [3,] 3 8 23 28# [4,] 4 9 24 29# [5,] 5 10 25 30
apply(X = hauteur, MARGIN = 1, FUN = mean)# [1] 13.5 14.5 15.5 16.5 17.5
?apply
Bien qu'il soit important de couvrir les diapositives de la famille de fonctions apply()
, le présentateur devrait envisager de les passer plus rapidement afin de s'assurer qu'il reste suffisamment de temps pour les sections plus importantes (c'est-à-dire le reste des composants du flux de contrôle, la section d'écriture des fonctions, ainsi que les exercices).
lapply()
lapply()
applique une fonction sur chaque élément d'une liste
.
lapply()
fonctionne aussi sur d'autres objets, comme des trames de données (“dataframe”) ou des vecteurs.
La sortie est une liste
(d'où le “l
” dans lapply
) ayant le même nombre d'éléments que l'objet d'entrée.
SimulatedData <- list( SimpleSequence = 1:4, Norm10 = rnorm(10), Norm20 = rnorm(20, 1), Norm100 = rnorm(100, 5))# Applique mean() sur chaque # élément de la listelapply(SimulatedData, mean)
# $SimpleSequence# [1] 2.5# # $Norm10# [1] -0.3780845# # $Norm20# [1] 0.8667661# # $Norm100# [1] 4.887815
sapply()
sapply()
est une fonction ‘wrapper’ pour lapply()
, qui produit une sortie simplifiée en vecteur
, au lieu d'une liste
.
SimulatedData <- list(SimpleSequence = 1:4, Norm10 = rnorm(10), Norm20 = rnorm(20, 1), Norm100 = rnorm(100, 5))
# Applique mean() sur chaque élément de la listesapply(SimulatedData, mean)# SimpleSequence Norm10 # 2.5000000 -0.1720864 # Norm20 Norm100 # 1.1226522 5.0647590
mapply()
mapply()
est une version multivariée de sapply()
.
mapply()
applique une fonction sur le premier élément de chaque argument, ensuite sur le deuxième élément, et ainsi de suite. Par exemple:
lilySeeds <- c(80, 65, 89, 23, 21)poppySeeds <- c(20, 35, 11, 77, 79)
# Outputmapply(sum, lilySeeds, poppySeeds)# [1] 100 100 100 100 100
tapply()
tapply()
applique une fonction sur des sous-ensembles d'un vecteur.
tapply()
est surtout utilisé quand un jeu de données contient différents groupes (i.e. niveaux ou facteurs), et lorsqu'on veut appliquer une fonction sur chaque groupe.
mtcars[1:10, c("hp", "cyl")]# hp cyl# Mazda RX4 110 6# Mazda RX4 Wag 110 6# Datsun 710 93 4# Hornet 4 Drive 110 6# Hornet Sportabout 175 8# Valiant 105 6# Duster 360 245 8# Merc 240D 62 4# Merc 230 95 4# Merc 280 123 6
# Moyenne de hp par cylindrestapply(mtcars$hp, mtcars$cyl, FUN = mean)# 4 6 8 # 82.63636 122.28571 209.21429
En revenant du terrain, vous vous êtes rendu compte que votre outil de mesure de l'absorption de CO2 n'était pas correctement calibré sur les sites du Québec et que toutes les mesures sont de 2 unités supérieures à ce qu'elles devraient être.
Utilisez une boucle pour corriger les mesures pour tous les sites aux Québec.
Utilisez une méthode vectorisée pour calculer la moyenne de l'absorption de CO2 dans les deux groupes de sites.
Pour cela, vous devez charger l'ensemble de données CO2 en utilisant
data(CO2)
, et ensuite utiliser l'objetCO2
.
for()
et if()
pour corriger les mesures:for (i in 1:dim(CO2)[1]) { if(CO2$Type[i] == "Quebec") { CO2$uptake[i] <- CO2$uptake[i] - 2 }}
tapply()
pour calculer la moyenne de chaque groupe de sites:tapply(CO2$uptake, CO2$Type, mean)# Quebec Mississippi # 31.54286 20.88333
Habituellement, les boucles itèrent successivement jusqu'à leur fin.
Il est parfois intéressant de modifier ce comportement.
Par exemple, on peut arrêter l'exécution de la boucle quand une certaine condition est satisfaite ou quand l'itération a atteint un certain élément.
On peut aussi sauter certains éléments selon certaines conditions, ou arrêter l'itération pour passer à la boucle suivante.
Pour ceci, on introduit break
, next
and while
.
les clauses if
et if
else
la boucle for
les clauses break
et next
la boucle repeat
la boucle while
break
for(val in x) { if(condition) { break } expression}
next
for(val in x) { if(condition) { next } expression}
next
Affiche les concentrations CO2 pour les traitements “chilled” et garder le compte du nombre d'itérations accomplies.
count <- 0for (i in 1:nrow(CO2)) { if (CO2$Treatment[i] == "nonchilled") next # Passer à l'itération suivante si c'est "nonchilled" count <- count + 1 print(CO2$conc[i])}print(count) # Affiche le nombre d'itérations accomplies.
# [1] 42
sum(CO2$Treatment == "nonchilled")# [1] 42
les clauses if
et if
else
la boucle for
les clauses break
et next
la boucle repeat
la boucle while
repeat
On pourrait aussi accomplir ceci avec une boucle repeat
et break
:
count <- 0i <- 0repeat { i <- i + 1 if (CO2$Treatment[i] == "nonchilled") next # sauter cette itération count <- count + 1 print(CO2$conc[i]) if (i == nrow(CO2)) break # rompre la boucle }print(count)
les clauses if
et if
else
la boucle for
les clauses break
et next
la boucle repeat
la boucle while
while
On pourrait aussi utiliser une boucle while
:
i <- 0count <- 0while (i < nrow(CO2)){ i <- i + 1 if (CO2$Treatment[i] == "nonchilled") next # sauter cette itération count <- count + 1 print(CO2$conc[i])}print(count)
Vous vous êtes rendu compte qu'un autre de vos outils ne fonctionnait pas correctement !
Aux sites situés au Mississippi, les concentrations de moins de 300 sont bien mesurés, mais les concentrations de plus de 300 étaient surestimées par 20 unités !
Votre mission est d'écrire une boucle pour corriger ces mesures pour les sites du Mississippi.
Truc. Assurez-vous de charger les données originales avant de faire l'exercice:
data(CO2)
for (i in 1:nrow(CO2)) { if(CO2$Type[i] == "Mississippi") { if(CO2$conc[i] < 300) next CO2$conc[i] <- CO2$conc[i] - 20 }}
Note: On peut écrire ceci de façon plus claire et concise:
for (i in 1:nrow(CO2)) { if(CO2$Type[i] == "Mississippi" && CO2$conc[i] >= 300) { CO2$conc[i] <- CO2$conc[i] - 20 }}
for()
et if()
Créons un graphique uptake versus concentration avec des points de couleurs différentes, ouù chaque couleur est associé à un type (Quebec ou Mississippi) et à un treatment (chilled ou nonchilled):
plot(x = CO2$conc, y = CO2$uptake, type = "n", cex.lab = 1.4, cex.axis = 1.5, cex.main = 1.5, cex.sub = 1.5, xlab = "CO2 concentration", ylab = "CO2 uptake")# type = "n" dit à R de ne pas afficher les pointsfor (i in 1:length(CO2[,1])) { if (CO2$Type[i] == "Quebec" & CO2$Treatment[i] == "nonchilled") { points(CO2$conc[i], CO2$uptake[i], col = "red") } if (CO2$Type[i] == "Quebec" & CO2$Treatment[i] == "chilled") { points(CO2$conc[i], CO2$uptake[i], col = "blue") } if (CO2$Type[i] == "Mississippi" & CO2$Treatment[i] == "nonchilled") { points(CO2$conc[i], CO2$uptake[i], col = "orange") } if (CO2$Type[i] == "Mississippi" & CO2$Treatment[i] == "chilled") { points(CO2$conc[i], CO2$uptake[i], col = "green") }}
for()
et if()
Créez un graphique concentration vs uptake, où chaque plante est représentée par des points de couleur différentes.
Points bonus si vous utilisez des boucles nichées!
plot(x = CO2$conc, y = CO2$uptake, type = "n", cex.lab=1.4, xlab = "CO2 concentration", ylab = "CO2 uptake")plants <- unique(CO2$Plant)for (i in 1:nrow(CO2)){ for (p in 1:length(plants)) { if (CO2$Plant[i] == plants[p]) { points(CO2$conc[i], CO2$uptake[i], col = p)}}}
Le gros du travail dans R
est fait par des fonctions. Elles sont utiles pour:
R
.
function_name <- function(argument1, argument2, ...) { expression... # Ce que la fonction fait return(valeur) # Optionnel, pour sortir le résultat de la fonction}
function_name <- function(argument1, argument2, ...) { expression... return(valeur)}
Les arguments sont les données fournies en entrée à votre fonction et contiennent l'information nécessaire pour que la fonction opère correctement.
Une fonction peut avoir entre 0 et une infinité d'arguments. Par exemple:
operations <- function(numero_1, numero_2, numero_3) { resultat <- (numero_1 + numero_2) * numero_3 print(resultat)}
operations(1, 2, 3)# [1] 9
En utilisant ce que vous avez appris précédemment sur le contrôle de flux, créez une fonction print_animal()
qui prend un animal
comme argument et donne les résultats suivants :
Pitou <- "chien"Minou <- "chat"print_animal(Pitou)# [1] "woof"print_animal(Minou)# [1] "miaou"
print_animal <- function(animal) { if (animal == "chien") { print("woof") } else if (animal == "chat") { print("miaou") }}
Les arguments peuvent aussi être optionnels, auquel cas on peut leur donner une valeur par défaut.
Ceci peut s'avérer utile si on utilise souvent une fonction avec les mêmes paramètres, mais qu'on veut tout de même garder la possibilité de changer leur valeur si nécessaire.
operations <- function(numero_1, numero_2, numero_3 = 3) { resultat <- (numero_1 + numero_2) * numero_3 print(resultat)}operations(1, 2, 3) # est équivalent à# [1] 9operations(1, 2)# [1] 9operations(1, 2, 2) # on peut toujours changer la valeur de numero_3# [1] 6
...
L'argument spécial ...
vous permet de passer des arguments à une autre fonction utilisée à l'intérieur de votre fonction. Ici, on utilise ...
pour passer des arguments à plot()
et à points()
.
plot.CO2 <- function(CO2, ...) { plot(x=CO2$conc, y=CO2$uptake, type="n", ...) for (i in 1:length(CO2[,1])){ if (CO2$Type[i] == "Quebec") { points(CO2$conc[i], CO2$uptake[i], col = "red", type = "p", ...) } else if (CO2$Type[i] == "Mississippi") { points(CO2$conc[i], CO2$uptake[i], col = "blue", type = "p", ...) } }}
plot.CO2(CO2, cex.lab=1.2, xlab="Concentration CO2", ylab="CO2 uptake")plot.CO2(CO2, cex.lab=1.2, xlab="Concentration CO2", ylab="CO2 uptake", pch=20)
...
L'argument spécial ...
vous permet de passer des arguments à une autre fonction utilisée à l'intérieur de votre fonction. Ici, on utilise ...
pour passer des arguments à plot()
et à points()
.
...
L'argument spécial ...
permet d'entrer un nombre indéfini d'arguments.
sum2 <- function(...){ args <- list(...) result <- 0 for (i in args) { result <- result + i } return (result)}
sum2(2, 3)# [1] 5sum2(2, 4, 5, 7688, 1)# [1] 7700
La dernière expression évaluée dans une fonction
devient la valeur de sortie.
myfun <- function(x) { if (x < 10) { 0 } else { 10 }}
myfun(5)# [1] 0myfun(15)# [1] 10
function()
sort la dernière valeur évaluée, même sans inclure la fonction return()
.
Utiliser return()
de façon explicite peut être utile si la boucle doit terminer tôt, sortir de la fonction, et sortir une valeur.
simplefun1 <- function(x) { if (x<0) return(x)}
Un seul objet (ou texte) de retour peut être renvoyé par une fonction. Par contre, ceci n'est pas une limite: on peut renovoyer une liste
contenant plusieurs objets.
simplefun2 <- function(x, y) { z <- x + y return(list("result" = z, "x" = x, "y" = y))}
simplefun2(1, 2)
# $result# [1] 3# # $x# [1] 1# # $y# [1] 2
En utilisant vos nouvelles connaissances de fonctions et de structures de contrôle, créez une fonction bigsum()
qui prend 2 arguments a
et b
, et:
0
si la somme de a
et b
est strictement inférieure à 50;a
et b
.Solution 1
bigsum <- function(a, b) { result <- a + b if (result < 50) { return(0) } else { return (result) }}
Solution 2
bigsum <- function(a, b) { result <- a + b if (result < 50) { 0 } else { result }}
Il est essentiel de pouvoir situer nos variables, et de savoir si elles sont définies et accessibles.
Les variables définies à l'intérieur d'une fonction ne sont pas accessibles à l'extérieur de la fonction!
Les variables définies à l'extérieur d'une fonction sont accessibles à l'intérieur, mais ce n'est jamais une bonne idée! Votre fonction ne fonctionnera plus si la variable extérieure est effacée!
var1 <- 3 # 'var1' est définie à l'extérieur de la fonctionvartest <- function() { a <- 4 # 'a' est définie a l'intérieur print(a) # affiche 'a' print(var1) # affiche 'var1'}a # on ne peut pas afficher 'a', car 'a' n'existe qu'à l'intérieur de la fonction# [1] -4 -3 -2 -1 0 1 2 3# [9] 4 5vartest() # cvartest() affiche 'a' et 'var1'# [1] 4# [1] 3rm(var1) # supprime 'var1'vartest() # la fonction ne fonctionne plus, car 'var1' n'existe plus!# [1] 4# Error in vartest(): object 'var1' not found
Truc obligatoire. Utilisez donc des arguments!
De plus, à l'intérieur d'une fonction, les noms d'arguments remplaceront les noms des autres variables.
var1 <- 3 # var1 est définie à l'extérieur de la fonctionvartest <- function(var1) { print(var1) # affiche var1}vartest(8) # Dans notre fonction, var1 est maintenant notre argument et prend sa valeur# [1] 8var1 # var1 a toujours la même valeur à l'extérieur de la fonction# [1] 3
Truc. Faites très attention lorsque vous créez des variables à l'intérieur d'une condition, car la variable pourrait ne jamais être créée et causer des erreurs (parfois imperceptibles).
Truc. Une bonne pratique serait de définir les variables à l'extérieur de la condition, puis ensuite de modifier leurs valeurs pour éviter ces problèmes.
a <- 3if (a > 5) { b <- 2}a + b
# Error: object 'b' not found
Si b
avait déjà une valeur différente assignée dans l'environnement, on aurait gros problème!
R ne trouverait pas d'erreur, et la valeur de a + b
serait entièrement différente!
Faites attention aux conseils suivants!
Les indentations et les espaces sont une première étape vers un code lisible:
<-
est préférable. Vous pouvez utiliser =
(parfois), mais ne changez pas entre les deux;else
.
Cmd + I
ou Ctrl + I
dans RStudio
pour indenter automatiquement le code mis en évidence.À gauche, le code n'est pas espacé. Tous les crochets sont sur une ligne, et le code paraît malpropre.
a<-4;b=3if(a<b){if(a==0)print("a zero")}else{if(b==0){print("b zero")}else print(b)}
À gauche, le code n'est pas espacé. Tous les crochets sont sur une ligne, et le code paraît malpropre. Le code à droite paraît mieux organisé, non?
a<-4;b=3if(a<b){if(a==0)print("a zero")}else{if(b==0){print("b zero")}else print(b)}
a <- 4b <- 3if(a < b){ if(a == 0) { print("a zero") }} else { if(b == 0){ print("b zero") } else { print(b) }}
Écrivez une fonction:
Ceci vous aidera à réduire le nombre d'erreurs de copier/coller, et réduira le temps passé à les corriger.
Modifions l'exemple de l'Exercice 3 et supposons que toutes les concentrations de CO2 du Mississipi étaient surestimées de 20 et que celles du Québec étaient sous-estimées de 50.
On pourrait écrire ceci:
for (i in 1:length(CO2[,1])) { if(CO2$Type[i] == "Mississippi") { CO2$conc[i] <- CO2$conc[i] - 20 }}for (i in 1:length(CO2[,1])) { if(CO2$Type[i] == "Quebec") { CO2$conc[i] <- CO2$conc[i] + 50 }}
Ou ceci:
recalibrate <- function(CO2, type, bias){ for (i in 1:nrow(CO2)) { if(CO2$Type[i] == type) { CO2$conc[i] <- CO2$conc[i] + bias } } return(CO2)}
newCO2 <- recalibrate(CO2 = CO2, type = "Mississipi", bias = -20)newCO2 <- recalibrate(newCO2, "Quebec", +50)
Voici notre fonction de l'exemple précédent avec un nom vague.
rc <- function(c, t, b) { for (i in 1:nrow(c)) { if(c$Type[i] == t) { c$conc[i] <- c$conc[i] + b } } return (c)}
Qu-est ce que c
et rc
?
Quand possible, évitez d'utiliser des noms de fonctions R
et de variables qui existent déjà pour éviter la confusion et les conflits.
Truc final. Ajoutez des commentaires pour décrire tout ce que votre code fait, que ce soit le but de la fonction, comment utiliser ses arguments, ou une description détaillée de la fonction étape par étape.
# Recalibre le jeu de données CO2 en modifiant la concentration de CO2# d'une valeur fixe selon la region# Arguments# CO2: the CO2 dataset# type: the type ("Mississippi" or "Quebec") that need to be recalibrated.# bias: the amount to add or remove to the concentrationrecalibrate <- function(CO2, type, bias) { for (i in 1:nrow(CO2)) { if(CO2$Type[i] == type) { CO2$conc[i] <- CO2$conc[i] + bias } } return(CO2)}
En utilisant ce que vous avez appris, écrivez une déclaration if()
qui vérifie si une variable numérique x
est égale à zéro. Si ce n'est pas le cas, elle attribue cos(x)/x à z
, sinon elle attribue 1 à z
.
Créez une fonction appelée ma_fonction()
qui prend la variable x
en argument et retourne z
.
Si nous attribuons respectivement 45, 20 et 0 à x
, laquelle des options suivantes représenterait les résultats ?
1. 0.054, 0.012, et 0;
2. 0.020, 0.054, et 1;
3. 0.012, 0.020, et 1.
En complément de l'exercice, discutez avec votre groupe d'une fonction que vous aimeriez créer (elle peut être liée ou non à votre recherche). Soyez prêts à nous la décrire brièvement!
Cet exercice doit avoir lieu dans les salles de réunion dans un délai de 10 minutes. Après avoir rejoint la salle principale, un sondage doit être ouvert aux participants. Une fois que vous avez obtenu la réponse des participants, montrez-leur la bonne réponse et le bon code. Vous pouvez demander à l'un des participants d'expliquer sa réponse avant de montrer les résultats.
La bonne réponse est l'option 3 ( 0.012, 0.020, et 1 ).
ma_fonction <- function(x) { if(x != 0) { z <- cos(x)/x } else { z <- 1 } return(z)}
ma_fonction(45)# [1] 0.01167382ma_fonction(20)# [1] 0.0204041ma_fonction(0)# [1] 1
Keyboard shortcuts
↑, ←, Pg Up, k | Go to previous slide |
↓, →, Pg Dn, Space, j | Go to next slide |
Home | Go to first slide |
End | Go to last slide |
Number + Return | Go to specific slide |
b / m / f | Toggle blackout / mirrored / fullscreen mode |
c | Clone slideshow |
p | Toggle presenter mode |
t | Restart the presentation timer |
?, h | Toggle this help |
Esc | Back to slideshow |
Étapes :
?unique
) ;for()
etif()
.