Fonctions
Les blocs entre parenthèses
Avant de passer aux fonctions, nous avons besoin de préciser quelques points sur les expressions. Les
expressions sont evaluées pour créer des objets. Elles sont constituées d.opérateurs (+, *, ^) et d.autres
objets (variables ou constantes) par exemple :
2 + 2, sin(x)^2.
a <- 2 + 2
a
[1] 4
b <- sin(a)^2
b
[1] 0.57275
Expression et objets : blocs
a des blocs d.expressions qui sont une suite d.expressions encadrées par des accolades. Toutes les expres-
sions d.un bloc sont evaluées les unes a la suite des autres. Tous les assignements de variables seront e¤ectifs
et tous les appels a
print() ou plot() auront les e¤ets collat attendus. Mais le plus important est que le bloc entier est lui-eme
une expression dont la valeur sera la derniere expression evaluée dans le bloc.
monbloc <- {
tmp <- 1:10
somme <- sum(tmp)
}
tmp
[1] 1 2 3 4 5 6 7 8 9 10
somme
2
[1] 55
monbloc
[1] 55
Dé?nition de la fonction :
hello <- function() {
print("Hello world")
}
Appel de la fonction :
hello()
[1] "Hello world"
Une fonction qui retourne ses arguments
mafonction <- function(a = 1, b = 2, c) {
resultat <- c(a, b, c)
names(resultat) <- c("a", "b", "c")
return(resultat)
}
mafonction(6, 7, 8)
a b c
6 7 8
1
mafonction(10, c = "bien")
a b c
"10" "2" "bien"
Pour une fonction donnée, la liste de ses arguments (avec les valeurs par défaut eventuelles) est donnée
par la fonction args() :
args(mafonction)
function (a = 1, b = 2, c)
NULL
Pour une fonction donnée, le corps de la fonction est donnée par la fonction body :
body(mafonction)
{
resultat <- c(a, b, c)
names(resultat) <- c("a", "b", "c")
return(resultat)
}
On peut aussi entrer le nom de la fonction sans les parenthéses pour avoir args()+body() :
mafonction
function (a = 1, b = 2, c)
{
resultat <- c(a, b, c)
names(resultat) <- c("a", "b", "c")
return(resultat)
}
Illustration de la portée des variable
mavariable <- 1
mafonction1 <- function() {
mavariable <- 5
print(mavariable)
}
mafonction1()
[1] 5
mavariable
[1] 1
mafonction2 <- function() {
print(mavariable)
}
mafonction2()
[1] 1
cube <- function {
carre <- function() n * n
n * carre()
}
cube(2)
Structures de controle
Faire des choix
if(cond) expr
Pour faire un choix simple :
f <- function(x) {
if (x%%2 == 0) {
return("pair")
}
}
f(2)
if(cond) expr1 else expr2
Pour faire choisir entre une condition et son alternative :
f <- function(x) {
if (x%%2 == 0) {
return("pair")
}
else {
return("impair")
}
}
f(2)
[1] "pair"
f(3)
[1] "impair"
[1] "pair"
f(3)
while. Tant que la condition est vraie on répéte l'expression :
i <- 1
while (i <= 5) {
print(i)
i <- i + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
switch(expr, ...). Pour faire des choix multiples :
f <- function(x) {
switch(x, "un", "deux", "trois", "quatre")
}
f(1)
[1] "un"
f(2)
[1] "deux"
f(5)
NULL
[1] 5
switch(expr, ) En travaillant avec une expression de type chaine de caractères on peut préciser un choix par défaut :
f <- function(chaine) {
switch(chaine, un = 1, deux = 2, trois = 3, quatre = 4,
"je ne sais pas")
}
f("un")
[1] 1
f("deux")
[1] 2
f("cent")
[1] "je ne sais pas"
ifelse(test, oui, non)
Il existe une version vectorisée trés puissante :
x <- rnorm(10)
x
[1] -0.47162735 -0.77978020 -1.07174132 -1.29467154 -0.47645939
[6] 0.52778427 0.49125277 -1.59025716 -2.74457419 -0.03007822
ifelse(x > 0, "positif", "negatif")
[1] "negatif" "negatif" "negatif" "negatif" "negatif" "positif"
[7] "positif" "negatif" "negatif" "negatif"
Repeter une action
On est souvent amené a faire des simulations pour apprécier la distribution d'échantillonnage d'une statistique. La fonction
replicate() permet de le faire trés facilement :
hist(replicate(500, mean(rnorm(100))), col = "lightblue")
for(var in seq) expr
On peut aussi faire des boucles explicites a l'ancienne :
for (i in 1:5) print(i)
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
for (carac in letters[1:5]) print(carac)
[1] "a"
[1] "b"
[1] "c"
[1] "d"
[1] "e"
for(var in seq) expr
Remplacer toutes les valeurs négatives d'un vecteur par -1.
Approche laborieuse classique :
x <- rnorm(10)
for (i in 1:length(x)) {
if (x[i] < 0)
x[i] <- -1
}x
[1] -1.00000000 0.57698909 0.52651301 -1.00000000 1.06504920
[6] 0.00999927 -1.00000000 0.71572971 -1.00000000 -1.00000000
Approche sous :
x <- rnorm(10)
x[x < 0] <- -1
x
[1] 0.99210114 0.81975449 2.21701969 1.46007751 0.01846901
[6] -1.00000000 -1.00000000 0.11346376 -1.00000000 -1.00000000
Remarque : on aurait pu utiliser aussi ici le if vectorisé ainsi :
x <- rnorm(10)
x <- ifelse(x < 0, -1, x)
x
[1] -1.0000000 1.3615624 1.5683767 1.1430187 -1.0000000 -1.0000000
[7] 0.4646724 1.1394565 -1.0000000 -1.0000000
while(cond) expr
Tant que la condition est vraie on répéte l'expression :
i <- 1
while (i <= 5) {
print(i)
i <- i + 1
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
repeat expr
On répéte l'expression tant qu'un break n'en fait pas sortir :
i <- 1
repeat {
print(i)
i <- i + 1
if (i > 5)
break
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
next
On peut sauter un tour dans une boucle. Par exemple pour mettre
a zéro tous leséléments d'une matrice sauf leséléments
diagonaux :
(x <- matrix(rnorm(9), 3, 3))
[,1] [,2] [,3]
[1,] 1.2478061 0.06974192 -0.1352661
[2,] 1.6225568 0.64071224 -0.5948983
[3,] 0.5394343 1.68095070 1.0463645
for (i in 1:3) {
for (j in 1:3) {
if (i == j)
next
x[i, j] <- 0
}
}x
[,1] [,2] [,3]
[1,] 1.247806 0.0000000 0.000000
[2,] 0.000000 0.6407122 0.000000
[3,] 0.000000 0.0000000 1.046365
Remarque : sous , on ferait plus simplement :
(x <- matrix(rnorm(9), 3, 3))
[,1] [,2] [,3]
[1,] 1.146043 -0.2329530 -0.1141616
[2,] 1.040547 -1.6224200 1.9552784
[3,] 0.954766 -0.8191705 -1.0065945
(x <- diag(diag(x)))
[,1] [,2] [,3]
[1,] 1.146043 0.00000 0.000000
[2,] 0.000000 -1.62242 0.000000
[3,] 0.000000 0.00000 -1.006594
Boucles implicites
lapply()
lapply() permet d'appliquer une fonction a tous leséléments
d'une liste ou d'un vecteur :
maliste <- as.list(1:3)
f <- function(x) x^2
lapply(maliste, f)
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 9
lapply() retourne une liste :
lapply(1:4, f)
[[1]]
[1] 1
[[2]]
[1] 4
[[3]]
[1] 9
[[4]]
[1] 16
sapply()
sapply() essaye de simpli er le résultat en un vecteur :
sapply(maliste, f)
[1] 1 4 9
sapply(1:10, f)
[1] 1 4 9 16 25 36 49 64 81 100
tapply()
La fonction tapply() permet d'appliquer une fonction a des groupes
dé nis par une variable qualitative :
data(iris)
head(iris)
Sepal.Length Sepal.Width Petal.Length Petal.Width Species
1 5.1 3.5 1.4 0.2 setosa
2 4.9 3.0 1.4 0.2 setosa
3 4.7 3.2 1.3 0.2 setosa
4 4.6 3.1 1.5 0.2 setosa
5 5.0 3.6 1.4 0.2 setosa
6 5.4 3.9 1.7 0.4 setosa
tapply(iris$Sepal.Length, iris$Species, mean)
setosa versicolor virginica
5.006 5.936 6.588
apply()
apply() permet d'appliquer une fonction aux lignes (1) ou aux
colonnes (2) d'une matrice :
(mat <- matrix(rpois(12, 2), 3, 4))
[,1] [,2] [,3] [,4]
[1,] 1 2 3 3
[2,] 3 3 3 1
[3,] 0 1 2 2
apply(mat, 1, sum)
[1] 9 10 5
apply(mat, 2, sum)
[1] 4 6 8 6
Remarque : les fonctions colSums() et rowSums() permettent
d'obtenir le m^eme r esultat :
rowSums(mat)
[1] 9 10 5
colSums(mat)
[1] 4 6 8 6
Exemple d'application : on considére le jeu de données airquality :
data(airquality)
head(airquality)
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
5 NA NA 14.3 56 5 5
6 28 NA 14.9 66 5 6
Il y a des données manquantes. Que faire ?
Premiere solution : ne garder que les individus entierement documentés :
head(airquality)
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
5 NA NA 14.3 56 5 5
6 28 NA 14.9 66 5 6
head(airquality[complete.cases(airquality), ])
Ozone Solar.R Wind Temp Month Day
1 41 190 7.4 67 5 1
2 36 118 8.0 72 5 2
3 12 149 12.6 74 5 3
4 18 313 11.5 62 5 4
7 23 299 8.6 65 5 7
8 19 99 13.8 59 5 8
Deuxi eme solution : remplacer les valeurs manquantes par la
moyenne de la variable. Approche a l'ancienne :
for (i in 1:nrow(airquality)) {
for (j in 1:ncol(airquality)) {
if (is.na(airquality[i, j])) {
airquality[i, j] <- mean(airquality[, j],
na.rm = TRUE)
}
}
}
head(airquality)
Ozone Solar.R Wind Temp Month Day
1 41.00000 190.0000 7.4 67 5 1
2 36.00000 118.0000 8.0 72 5 2
3 12.00000 149.0000 12.6 74 5 3
4 18.00000 313.0000 11.5 62 5 4
5 42.12931 185.9315 14.3 56 5 5
6 28.00000 185.9315 14.9 66 5 6
Approche avec apply() :
data(airquality)
head(apply(airquality, 2, function(x) ifelse(is.na(x),
mean(x, na.rm = TRUE), x)))
Ozone Solar.R Wind Temp Month Day
[1,] 41.00000 190.0000 7.4 67 5 1
[2,] 36.00000 118.0000 8.0 72 5 2
[3,] 12.00000 149.0000 12.6 74 5 3
[4,] 18.00000 313.0000 11.5 62 5 4
[5,] 42.12931 185.9315 14.3 56 5 5
[6,] 28.00000 185.9315 14.9 66 5 6