Cette page comporte l’ensemble des cas pratiques de la formation R perfectionnement donnée à la Drees les 16 et 17 avril 2018 accompagnés de leur correction.
Les supports de cette formation ont été conçus sous RStudio avec R Markdown et compilés le 10/04/2018. Certains éléments de mise en forme du site compagnon sont repris de l’ouvrage R packages de Hadley Wickham.
Ces supports seront durablement disponibles à l’adresse http:// t.slmc.fr/perf et leur code source sur github. L’ensemble est librement réutilisable sous © 2016-2018 Martin Chevalier CC BY-NC-SA 3.0.
*apply()
, do.call()
et Reduce()
Le package microbenchmark
est souvent utilisé dans cette partie et les suivantes pour mesurer la performance des des solutions testées :
install.packages("microbenchmark")
library(microbenchmark)
Tout ce qui se passe dans R correspond à un appel de fonction. Comprendre le fonctionnement des fonctions et savoir en créer soi-même est donc crucial.
Utilisez les guillemets simples inversés (AltGr + 7 sur le clavier azerty) pour afficher le code associé au signe +
. Utilisez-le comme une fonction classique avec la syntaxe nomFonction(parametre1, parametre2)
.
Définissez la fonction monCalcul(x, puissance)
qui pour un vecteur numérique x
quelconque :
calcule sa somme ;
met la somme à la puissance puissance
.
Dans un second temps, donnez à puissance
la valeur 2
par défaut et faites en sorte que la fonction prenne en charge les vecteurs x
présentant des valeurs manquantes NA
.
Modifier la fonction pour ajouter une étape de vérification du type de x
: prévoyez un message d’erreur si x
est de type character
ou factor
.
Quelle est la valeur de l’objet T
? Comment expliquez-vous que cet objet soit défini alors que vous ne l’avez pas vous-même créé (vous pouvez utiliser la fonction getAnywhere()
pour répondre) ?
Soumettez le code T <- 3
. Que vaut désormais l’objet T
? Pourquoi R n’accède-t-il plus à la valeur stockée par défaut (vous pouvez utiliser la fonction search()
pour répondre) ? Comment accéder désormais à la valeur par défaut ? Que retenez-vous quant à l’utilisation de T
et de F
en lieu et place de TRUE
et FALSE
dans un code ?
apply()
: Appliquer une fonction selon les dimensions d’une matriceCréez une matrice e1
de 3 lignes et de 5 colonnes en utilisant la fonction runif()
. Ses valeurs sont-elles identiques si vous la générez une seconde fois ? Comment faire pour que cela soit le cas ?
Utilisez la fonction apply()
pour calculer la somme des termes de chaque ligne de e1
. Comment auriez-vous pu faire autrement ? Utilisez la fonction microbenchmark()
pour comparer ces deux solutions.
Utilisez la fonction apply()
pour centrer-réduire toutes les colonnes de e1
(i.e. leur soustraire leur moyenne puis les diviser par leur écart-type).
lapply()
et sapply()
: Appliquer une fonction aux éléments d’un vecteur, d’une liste ou aux colonnes d’un data.frameOn définit le vecteur f1
par f1 <- 5:15
. Utilisez la fonction sapply()
pour calculer la somme cumulée des éléments de f1
. Quelle(s) alternative(s) envisageriez-vous ? Utilisez la fonction microbenchmark()
pour comparer ces solutions.
On définit la liste f2
par
f2 <- list(
sample.int(26, 10, replace = TRUE)
, sample.int(26, 100, replace = TRUE)
, sample.int(26, 1000, replace = TRUE)
)
Utilisez les fonctions lapply()
ou sapply()
pour :
f2
;f2
;remplacer chaque élément de f2
par le vecteur de lettres (en minuscules) dont il représente les positions dans l’alphabet.
On définit le data.frame
f3
par
set.seed(1)
f3 <- data.frame(
id = letters[1:20]
, by = rep(letters[1:5], times = 4)
, matrix(runif(100), ncol = 5)
, stringsAsFactors = FALSE
)
Utilisez les fonctions lapply()
ou sapply()
pour :
f3
;f3
;character
en facteurs.
tapply()
: Appliquer une fonction selon les modalités d’un vecteurg1 <- sample(20)
et le vecteur g2 <- rep(c("H", "F"), times = 10)
. Utilisez tapply()
pour calculer la moyenne de g1
selon les groupes définis par g2
.
data.frame
f3
du cas pratique précédent. Utilisez tapply()
pour calculer le total de la variable X1
selon les modalités de la variable by
.
Combinez la fonction split()
avec sapply()
pour obtenir le même résultat. Comment calculeriez-vous le total de toutes les variables numériques de f3
selon les modalités de la variable by
?
do.call()
: Appliquer une fonction simultanément à l’ensemble des éléments d’une listeDe nombreuses fonctions peuvent porter sur un nombre indéterminé d’éléments : c()
, sum()
, rbind()
, etc. Pour les appliquer à l’ensemble des éléments d’une liste sans avoir à tous les écrire un à un, il suffit d’utiliser do.call()
.
On définit la liste h1 <- list(1:5, 6:10, 11:15)
. Que se passe-t-il si vous soumettez sum(h1)
? Utilisez do.call()
pour sommer l’ensemble des éléments de h1
. Comparez avec le résultat de sapply(h1, sum)
.
Réunissez les éléments de h1
en un seul vecteur avec la fonction base::c()
. Comparez avec le résultat de lapply(h1, base::c)
On définit la liste de matrices h2
h2 <- list(
matrix(1:6, nrow = 2)
, matrix(7:12, nrow = 2)
, matrix(13:18, nrow = 2)
)
do.call()
avec les fonctions rbind()
et cbind()
pour concaténer l’ensemble des éléments de h2
en ligne ou en colonne respectivement.
Reduce()
: Appliquer une fonction successivement à l’ensemble des éléments d’une listeDe nombreuses fonctions portent sur deux éléments précisément : opérations arithmétiques, merge()
, etc. Pour les appliquer successivement à l’ensemble des éléments d’une liste, il suffit d’utiliser Reduce()
.
On repart de la liste h1
du cas pratique précédent. Observez le résultat de Reduce(`+`, h1)
: comment le comprenez-vous ? Comparez avec sapply(h1, sum)
.
On définit la liste de data.frame
i1
i1 <- list(
data.frame(id = letters[1:4], var1 = 1:4, stringsAsFactors = FALSE)
, data.frame(id = letters[2:5], var2 = 5:8, stringsAsFactors = FALSE)
, data.frame(id = letters[3:6], var3 = 9:12, stringsAsFactors = FALSE)
)
Reduce()
pour fusionner l’ensemble des éléments de i1
selon la variable id
. Comment ajusteriez-vous ce code pour pouvoir utiliser l’option all = TRUE
de la fonction merge()
?
L’ensemble des cas pratiques qui suivent portent sur les données de l’enquête Emploi en continu stockées dans le fichier eect4.rds
. La fonction readRDS()
permet de le charger en mémoire :
setwd("Y:/Documentation/R/R_perfectionnement/donnees")
eec <- readRDS("eect4.rds")
str(eec)
## 'data.frame': 34913 obs. of 19 variables:
## $ IDENT : chr "G0A56JP6" "G0A56JP6" "G0A56JR6" "G0A56JS6" ...
## $ TRIM : chr "4" "4" "4" "4" ...
## $ NOI : chr "01" "02" "01" "01" ...
## $ REG : chr "11" "11" "11" "11" ...
## $ AGE : chr "66" "29" "27" "29" ...
## $ SEXE : chr "2" "1" "2" "2" ...
## $ CSE : chr "56" "81" "38" "37" ...
## $ DIP11 : chr "71" "42" "10" "11" ...
## $ ACTEU : chr "1" "2" "1" "1" ...
## $ SALRED : int 596 NA 2700 2666 11967 NA 2000 2800 2333 3500 ...
## $ STC : chr "2" NA "2" "2" ...
## $ TAM1D : chr NA NA NA NA ...
## $ AIDREF : chr NA "5" NA NA ...
## $ TPP : chr "1" NA "1" "1" ...
## $ NBAGENF : chr "0" "0" "0" "0" ...
## $ DUHAB : chr "7" NA "7" "7" ...
## $ PUB3FP : chr "4" NA "4" "4" ...
## $ NAIA : chr "1946" "1983" "1985" "1983" ...
## $ EXTRI1613: num 1777 1777 2045 1898 1754 ...
Utilisez l’opérateur [
pour sélectionner l’individu appartenant au ménage dont l’IDENT
est "GFO5NVUE"
et dont le numéro d’ordre NOI
est "02"
.
Cherchez de la documentation sur la fonction subset()
. Comparez ses performances avec celles de l’opérateur [
à l’aide de la fonction microbenchmark()
.
Concaténez les valeurs des variables IDENT
et NOI
et utilisez le résultat comme noms de ligne. Retrouvez alors l’individu de la question a à l’aide de son nom de ligne. Comparez les performances de cette méthode avec celles de l’opérateur [
.
On souhaite recoder la variable AGE
en trois modalités : 15-30 ans, 31-60 ans et plus de 60 ans. On part du code suivant :
for(i in 1:nrow(eec)) eec$trage1[i] <- if(as.numeric(eec$AGE[i]) < 31) "15-30" else if(as.numeric(eec$AGE[i]) < 61) "31-60" else "61 et +"
Mesurez le temps d’exécution du code proposé. Que pensez-vous de cette syntaxe ?
On propose une seconde version du code :
eec$trage2 <- ifelse(as.numeric(eec$AGE) < 31, "15-30", ifelse(
as.numeric(eec$AGE) < 61, "31-60", "61 et +"
))
Vérifiez que le résultat est identique à la proposition initiale (par exemple avec identical()
ou all.equal()
) et mesurez le temps temps d’exécution de cette deuxième version. Êtes-vous surpris du gain de performances ?