library(dplyr)
Attachement du package : 'dplyr'
Les objets suivants sont masqués depuis 'package:stats':
filter, lag
Les objets suivants sont masqués depuis 'package:base':
intersect, setdiff, setequal, union
R
library(dplyr)
Attachement du package : 'dplyr'
Les objets suivants sont masqués depuis 'package:stats':
filter, lag
Les objets suivants sont masqués depuis 'package:base':
intersect, setdiff, setequal, union
Les listes sont des objets très utiles en R
et en particulier pour produire efficacement les tableaux de données et les informations nécessaires lorsque nous utilisons la fonction tab_multi_manager()
du package rtauargus
.
Alors qu’un vecteur en R
est une collection d’objets du même type, une liste est une collection d’objets qui peuvent être très différents entre eux. On peut ainsi créer, avec la fonction list()
, une liste contenant un vecteur d’entiers, un vecteur de charactères et un data.frame
:
<- list(1:3, c("spam", "egg"), head(cars))) (liste_1
[[1]]
[1] 1 2 3
[[2]]
[1] "spam" "egg"
[[3]]
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
Pour accéder aux éléments d’une liste, il faut distinguer deux types d’indexation:
avec les crochets simples: liste_1[1]
va permettre de récupérer la liste composée uniquement du premier objet. Cette indexation renvoie une liste. On utilisera ce type d’indexation pour extraire une sous-liste d’une liste: liste_1[2:3]
permet, par exemple, d’extraire la sous-liste composée des éléments 2 et 3 de la liste.
avec les crochets doubles: liste_1[[1]]
permet d’accéder au premier élément de la liste. Le type de l’objet renvoyé est le type de l’objet placé dans la liste à l’index renseigné (dans notre cas un vecteur d’entiers). On utilisera cette indexation pour extraire un objet particulier de la liste.
1] liste_1[
[[1]]
[1] 1 2 3
class(liste_1[1])
[1] "list"
1]] liste_1[[
[1] 1 2 3
class(liste_1[[1]])
[1] "integer"
Pour ajouter un élément à une liste, plusieurs techniques sont possibles:
c()
:<- list(LETTERS, head(mtcars))) (liste_2
[[1]]
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
[[2]]
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
<- c(liste_1, liste_2)) (liste_3
[[1]]
[1] 1 2 3
[[2]]
[1] "spam" "egg"
[[3]]
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
[[4]]
[1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S"
[20] "T" "U" "V" "W" "X" "Y" "Z"
[[5]]
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4
Datsun 710 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1
Hornet 4 Drive 21.4 6 258 110 3.08 3.215 19.44 1 0 3 1
Hornet Sportabout 18.7 8 360 175 3.15 3.440 17.02 0 0 3 2
Valiant 18.1 6 225 105 2.76 3.460 20.22 1 0 3 1
length(liste_3)
[1] 5
6] <- pi
liste_3[length(liste_3)
[1] 6
Si on ajoute un élément à un index supérieur à la longueur de la liste + 1, R
va créer automatiquement des éléments vides (de type NULL
) sur les index “oubliés”. Ici, notre liste_3
contient 6 objets, si j’ajoute un élément à l’index 9
, la liste aura une longueur de 9
avec deux objets NULL
en positions 7
et 8
:
9] <- pi^2
liste_3[length(liste_3)
[1] 9
7:8] liste_3[
[[1]]
NULL
[[2]]
NULL
Il est souvent pratique de donner des noms à chaque élément de la liste. Cela permet de récupérer les objets sans avoir à connaître leur position dans la liste. La fonction names()
permet d’accoler un nom à chaque élément de la liste. On fera bien attention à fournir un vecteur de noms qui soit de la même longueur que la liste.
names(liste_1) <- c("vec_int", "vec_char", "cars_df")
names(liste_1)
[1] "vec_int" "vec_char" "cars_df"
liste_1
$vec_int
[1] 1 2 3
$vec_char
[1] "spam" "egg"
$cars_df
speed dist
1 4 2
2 4 10
3 7 4
4 7 22
5 8 16
6 9 10
Pour récupérer un élément de la liste grçace à son nom, on pourra utiliser les deux types d’indexation vues ci-dessus en utilisant non pas les index de position dans la liste mais les noms des objets.
Pour récupérer une sous-liste, on fera:
"vec_char"] # retourne une sous-liste d'un élément liste_1[
$vec_char
[1] "spam" "egg"
c("vec_int", "vec_char")] # retourne une sous-liste de deux éléments liste_1[
$vec_int
[1] 1 2 3
$vec_char
[1] "spam" "egg"
Pour retourner un objet de la liste, on fera:
"vec_char"]] # retourne l'élément vec_char en tant que vecteur liste_1[[
[1] "spam" "egg"
L’accès à un objet d’une liste est aussi possible en utilisant le $
. Ainsi, l’écriture suivante est identique à la précédente:
$vec_char liste_1
[1] "spam" "egg"
On pourra nommer les éléments d’une liste au moment de la créer:
<- list(
liste_df df1 = cars,
df2 = mtcars,
df3 = iris,
df4 = CO2
)names(liste_df)
[1] "df1" "df2" "df3" "df4"
On utilisera le code suivant pour supprimer le troisième élément d’une liste:
-3] liste_1[
$vec_int
[1] 1 2 3
$vec_char
[1] "spam" "egg"
Et le code suivant pour supprimer les éléments 7 et 8 de liste_3
length(liste_3[c(-7,-8)])
[1] 7
lapply()
Pour cette section, nous utiliserons principalement des listes dont tous les éléments sont du même type, en particulier des data.frames
.
Pour appliquer une même fonction à tous les éléments d’une liste, il n’est pas besoin d’écrire une boucle for
car la fonction lapply()
s’en charge pour nous.
Un premier exemple: Nous souhaitons connaître les dimensions de chaque data.frame
qui compose la liste liste_df
. Le premier argument de lapply
est la liste sur laquelle nous travaillons et le second argument est la fonction que nous voulons appliquer sur chaque élément. Il s’agit, ici, de la fonction dim()
.
lapply(liste_df, dim)
$df1
[1] 50 2
$df2
[1] 32 11
$df3
[1] 150 5
$df4
[1] 84 5
La fonction lapply()
retourne une liste de même longueur que la liste de départ et chaque élément de la liste contient le résultat de la fonction dim()
soit un vecteur de deux éléments (nombre de lignes et nombre de colonnes d’un data.frame
).
Second exemple: Nous souhaitons afficher les deux premières lignes de chaque data.frame
. Ici, nous allons utiliser la fonction head()
qui affiche, par défaut les 6 premières lignes. Il nous faut donc changer un paramètre de la fonction. Nous pouvons:
lapply(liste_df, function(df) head(df, n = 2))
$df1
speed dist
1 4 2
2 4 10
$df2
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
$df3
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
$df4
Plant Type Treatment conc uptake
1 Qn1 Quebec nonchilled 95 16.0
2 Qn1 Quebec nonchilled 175 30.4
lapply(liste_df, \(df) head(df, n = 2)) # écriture de fonction apparue avec R 4.2
$df1
speed dist
1 4 2
2 4 10
$df2
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
$df3
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
$df4
Plant Type Treatment conc uptake
1 Qn1 Quebec nonchilled 95 16.0
2 Qn1 Quebec nonchilled 175 30.4
Dans cette écriture df
prendra successivement comme valeur les objets de la liste, comme le i
dans une boucle for(i in ...)
.
df
) de la manière suivante:lapply(liste_df, head, n = 2)
$df1
speed dist
1 4 2
2 4 10
$df2
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4
Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4
$df3
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
$df4
Plant Type Treatment conc uptake
1 Qn1 Quebec nonchilled 95 16.0
2 Qn1 Quebec nonchilled 175 30.4
Troisième exemple: Nous souhaitons, dans chacun des tableaux, ajouter une variable servant d’identifiant.
<- lapply(
liste_df2
liste_df, function(df){
$index <- 1:nrow(df)
dfreturn(df)
}
)lapply(liste_df2, head, n=2)
$df1
speed dist index
1 4 2 1
2 4 10 2
$df2
mpg cyl disp hp drat wt qsec vs am gear carb index
Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4 1
Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4 2
$df3
Sepal.Length Sepal.Width Petal.Length Petal.Width Species index
1 5.1 3.5 1.4 0.2 setosa 1
2 4.9 3.0 1.4 0.2 setosa 2
$df4
Plant Type Treatment conc uptake index
1 Qn1 Quebec nonchilled 95 16.0 1
2 Qn1 Quebec nonchilled 175 30.4 2
purrr::map()
La package purrr
met à disposition des fonctions qui permettent de manipuler les listes. Une aide précieuse pour découvrir tous les trésors du package est fournie ici:
library(purrr)
map()
est un équivalent de la fonction lapply()
:map(liste_df, dim)
$df1
[1] 50 2
$df2
[1] 32 11
$df3
[1] 150 5
$df4
[1] 84 5
L’avantage du package est de fournir des variantes très utiles de la fonction map()
, en particulier la fonction imap()
qui permet d’accéder non pas seulement à tous les éléments de la liste mais aussi à leur index ou à leur nom.
Par exemple, imaginons que nous souhaitons ajouter à chaque data.frame
de la liste liste_df
une variable contenant le nom du tableau. Avec la fonction imap()
cela s’écrit:
<- imap(liste_df, \(df, nom) df %>% mutate(tableau = nom))
liste_df map(liste_df, head, n = 2)
$df1
speed dist tableau
1 4 2 df1
2 4 10 df1
$df2
mpg cyl disp hp drat wt qsec vs am gear carb tableau
Mazda RX4 21 6 160 110 3.9 2.620 16.46 0 1 4 4 df2
Mazda RX4 Wag 21 6 160 110 3.9 2.875 17.02 0 1 4 4 df2
$df3
Sepal.Length Sepal.Width Petal.Length Petal.Width Species tableau
1 5.1 3.5 1.4 0.2 setosa df3
2 4.9 3.0 1.4 0.2 setosa df3
$df4
Plant Type Treatment conc uptake tableau
1 Qn1 Quebec nonchilled 95 16.0 df4
2 Qn1 Quebec nonchilled 175 30.4 df4
Avec imap()
, la fonction anonyme n’a plus un mais deux arguments: l’un (que nous appelons df
ici) représente chaque objet de la liste et l’autre (nommé nom
ici) représente le nom de chaque élément. Ainsi, pour le premier élément, df
prendra la valeur liste_df[[1]]
et nom
prendra la valeur df1
.
data.frames
L’utilisation des listes est nécessaire pour utiliser la fonction tab_muli_manager
de rtauargus
. Mais, elle est aussi intéressante en amont, par exemple dans la pose du secret primaire comme dans l’exemple fourni à la section 4.2.
<- liste_4tabs %>%
liste_4tabs map(
function(df){
%>%
df mutate(
is_secret_freq = N_OBS > 0 & N_OBS < 3,
is_secret_dom = (MAX != 0) & (MAX > TOT*0.85),
is_secret_prim = is_secret_freq | is_secret_dom
)
} )
Le code ci-dessus permet d’appliquer à chacun des 4 data.frames
qui composent la liste liste_4tabs
une fonction anonyme qui:
is_secret_freq
, permettant d’indiquer si une cellule respecte ou non la règle de fréquence (avec les règles des statistiques entreprises);is_secret_dom
, permettant d’indiquer si une cellule respecte ou non la règle de dominance;is_secret_prim
, permettant d’indiquer si une cellule respecte ou non les deux règles à la fois.En sortie, nous obtiendrons ainsi une liste composés des mêmes 4 data.frames
qui auront chacun les trois variables de secret primaire construites ici en plus.