Guide R
Guide R
Guide R
Joseph Larmarange
21 février 2024
Table des matières
Préface 15
Remerciements . . . . . . . . . . . . . . . . . . . . . . 17
Licence . . . . . . . . . . . . . . . . . . . . . . . . . . 17
I Bases du langage 18
1 Packages 19
1.1 Installation (CRAN) . . . . . . . . . . . . . . . . 20
1.2 Chargement . . . . . . . . . . . . . . . . . . . . . 20
1.3 Mise à jour . . . . . . . . . . . . . . . . . . . . . 21
1.4 Installation depuis GitHub . . . . . . . . . . . . . 22
1.5 Le tidyverse . . . . . . . . . . . . . . . . . . . . . 23
2 Vecteurs 26
2.1 Types et classes . . . . . . . . . . . . . . . . . . . 26
2.2 Création d’un vecteur . . . . . . . . . . . . . . . 27
2.3 Longueur d’un vecteur . . . . . . . . . . . . . . . 30
2.4 Combiner des vecteurs . . . . . . . . . . . . . . . 31
2.5 Vecteurs nommés . . . . . . . . . . . . . . . . . . 31
2.6 Indexation par position . . . . . . . . . . . . . . 33
2.7 Indexation par nom . . . . . . . . . . . . . . . . 34
2.8 Indexation par condition . . . . . . . . . . . . . . 35
2.9 Assignation par indexation . . . . . . . . . . . . 39
2.10 En résumé . . . . . . . . . . . . . . . . . . . . . . 40
2.11 webin-R . . . . . . . . . . . . . . . . . . . . . . . 41
3 Listes 42
3.1 Propriétés et création . . . . . . . . . . . . . . . 42
3.2 Indexation . . . . . . . . . . . . . . . . . . . . . . 45
3.3 En résumé . . . . . . . . . . . . . . . . . . . . . . 49
3.4 webin-R . . . . . . . . . . . . . . . . . . . . . . . 49
2
4 Tableaux de données 50
4.1 Propriétés et création . . . . . . . . . . . . . . . 50
4.2 Indexation . . . . . . . . . . . . . . . . . . . . . . 52
4.3 Afficher les données . . . . . . . . . . . . . . . . . 56
4.4 En résumé . . . . . . . . . . . . . . . . . . . . . . 65
4.5 webin-R . . . . . . . . . . . . . . . . . . . . . . . 65
5 Tibbles 66
5.1 Le concept de tidy data . . . . . . . . . . . . . . 66
5.2 tibbles : des tableaux de données améliorés . . . 66
5.3 Données et tableaux imbriqués . . . . . . . . . . 71
6 Attributs 74
II Manipulation de données 77
7 Le pipe 78
7.1 Le pipe natif de R : |> . . . . . . . . . . . . . . . 79
7.2 Le pipe du tidyverse : %>% . . . . . . . . . . . . . 80
7.3 Vaut-il mieux utiliser |> ou %>% ? . . . . . . . . . 81
7.4 Accéder à un élément avec purrr::pluck() et
purrr::chuck() . . . . . . . . . . . . . . . . . . 82
8 dplyr 85
8.1 Opérations sur les lignes . . . . . . . . . . . . . . 86
8.1.1 filter() . . . . . . . . . . . . . . . . . . . . 86
8.1.2 slice() . . . . . . . . . . . . . . . . . . . . 91
8.1.3 arrange() . . . . . . . . . . . . . . . . . . 92
8.1.4 slice_sample() . . . . . . . . . . . . . . . 94
8.1.5 distinct() . . . . . . . . . . . . . . . . . . 95
8.2 Opérations sur les colonnes . . . . . . . . . . . . 97
8.2.1 select() . . . . . . . . . . . . . . . . . . . 97
8.2.2 relocate() . . . . . . . . . . . . . . . . . . 102
8.2.3 rename() . . . . . . . . . . . . . . . . . . 103
8.2.4 rename_with() . . . . . . . . . . . . . . . 104
8.2.5 pull() . . . . . . . . . . . . . . . . . . . . 105
8.2.6 mutate() . . . . . . . . . . . . . . . . . . . 105
8.3 Opérations groupées . . . . . . . . . . . . . . . . 106
8.3.1 group_by() . . . . . . . . . . . . . . . . . 106
8.3.2 summarise() . . . . . . . . . . . . . . . . . 111
8.3.3 count() . . . . . . . . . . . . . . . . . . . 113
3
8.3.4 Grouper selon plusieurs variables . . . . . 114
8.4 Cheatsheet . . . . . . . . . . . . . . . . . . . . . 119
8.5 webin-R . . . . . . . . . . . . . . . . . . . . . . . 119
4
13.2.3 Conversion . . . . . . . . . . . . . . . . . 184
5
16.3 Palettes de couleurs . . . . . . . . . . . . . . . . 211
16.3.1 Color Brewer . . . . . . . . . . . . . . . . 211
16.3.2 Palettes de Paul Tol . . . . . . . . . . . . 213
16.3.3 Interface unifiée avec {paletteer} . . . . 215
6
19 Statistique bivariée & Tests de comparaison 275
19.1 Deux variables catégorielles . . . . . . . . . . . . 275
19.1.1 Tableau croisé avec gtsummary . . . . . . 275
19.1.2 Représentations graphiques . . . . . . . . 278
19.1.3 Calcul manuel . . . . . . . . . . . . . . . 285
19.1.4 Test du Chi² et dérivés . . . . . . . . . . . 288
19.1.5 Comparaison de deux proportions . . . . 290
19.2 Une variable continue selon une variable catégo-
rielle . . . . . . . . . . . . . . . . . . . . . . . . . 294
19.2.1 Tableau comparatif avec gtsummary . . . 294
19.2.2 Représentations graphiques . . . . . . . . 296
19.2.3 Calcul manuel . . . . . . . . . . . . . . . 302
19.2.4 Tests de comparaison . . . . . . . . . . . 303
19.2.5 Différence de deux moyennes . . . . . . . 306
19.3 Deux variables continues . . . . . . . . . . . . . . 307
19.3.1 Représentations graphiques . . . . . . . . 307
19.3.2 Tester la relation entre les deux variables 314
19.4 Matrice de corrélations . . . . . . . . . . . . . . . 315
19.5 webin-R . . . . . . . . . . . . . . . . . . . . . . . 317
7
22.9 Régressions logistiques univariées . . . . . . . . . 365
22.10Présenter l’ensemble des résultats dans un même
tableau . . . . . . . . . . . . . . . . . . . . . . . 367
22.11webin-R . . . . . . . . . . . . . . . . . . . . . . . 369
8
25.2 Contrastes de type somme . . . . . . . . . . . . . 444
25.2.1 Exemple 1 : un modèle linéaire avec une
variable catégorielle . . . . . . . . . . . . 444
25.2.2 Exemple 2 : une régression logistique avec
deux variables catégorielles . . . . . . . . 448
25.3 Contrastes par différences successives . . . . . . . 450
25.3.1 Exemple 1 : un modèle linéaire avec une
variable catégorielle . . . . . . . . . . . . 451
25.3.2 Exemple 2 : une régression logistique avec
deux variables catégorielles . . . . . . . . 452
25.4 Autres types de contrastes . . . . . . . . . . . . . 455
25.4.1 Contrastes de type Helmert . . . . . . . . 455
25.4.2 Contrastes polynomiaux . . . . . . . . . . 457
25.5 Lectures additionnelles . . . . . . . . . . . . . . . 458
26 Interactions 459
26.1 Données d’illustration . . . . . . . . . . . . . . . 459
26.2 Modèle sans interaction . . . . . . . . . . . . . . 460
26.3 Définition d’une interaction . . . . . . . . . . . . 462
26.4 Significativité de l’interaction . . . . . . . . . . . 464
26.5 Interprétation des coefficients . . . . . . . . . . . 466
26.6 Définition alternative de l’interaction . . . . . . . 471
26.7 Identifier les interactions pertinentes . . . . . . . 475
26.8 Pour aller plus loin . . . . . . . . . . . . . . . . . 477
26.9 webin-R . . . . . . . . . . . . . . . . . . . . . . . 478
27 Multicolinéarité 479
27.1 Définition . . . . . . . . . . . . . . . . . . . . . . 479
27.2 Mesure de la colinéarité . . . . . . . . . . . . . . 481
27.3 La multicolinéarité est-elle toujours un problème ?487
27.4 webin-R . . . . . . . . . . . . . . . . . . . . . . . 489
9
29 Manipulation de données pondérées 502
29.1 Utilisation de {srvyr} . . . . . . . . . . . . . . . 503
29.2 Lister / Rechercher des variables . . . . . . . . . 505
29.3 Extraire un sous-échantillon . . . . . . . . . . . . 506
10
34.3 Durées, périodes, intervalles & Arithmétique . . . 567
34.3.1 Durées (Duration) . . . . . . . . . . . . . 567
34.3.2 Périodes (Period) . . . . . . . . . . . . . . 570
34.3.3 Intervalles (Interval) . . . . . . . . . . . . 573
34.4 Calcul d’un âge . . . . . . . . . . . . . . . . . . . 576
34.5 Fuseaux horaires . . . . . . . . . . . . . . . . . . 577
34.6 Pour aller plus loin . . . . . . . . . . . . . . . . . 580
11
37 Conditions logiques 615
37.1 Opérateurs de comparaison . . . . . . . . . . . . 615
37.2 Comparaison et valeurs manquantes . . . . . . . 618
37.3 Opérateurs logiques (algèbre booléenne) . . . . . 620
37.3.1 Opérations logiques et Valeurs manquantes622
37.3.2 L’opérateur %in% . . . . . . . . . . . . . . 623
37.4 Aggrégation . . . . . . . . . . . . . . . . . . . . . 623
37.5 Programmation . . . . . . . . . . . . . . . . . . . 624
12
39.6 Lectures additionnelles . . . . . . . . . . . . . . . 668
13
43 Modèles de comptage (Poisson & apparentés) 736
43.1 Modèle de Poisson . . . . . . . . . . . . . . . . . 736
43.1.1 Préparation des données du premier
exemple . . . . . . . . . . . . . . . . . . . 737
43.1.2 Calcul & Interprétation du modèle de
Poisson . . . . . . . . . . . . . . . . . . . 739
43.1.3 Évaluation de la surdispersion . . . . . . . 743
43.2 Modèle de quasi-Poisson . . . . . . . . . . . . . . 747
43.3 Modèle binomial négatif . . . . . . . . . . . . . . 750
43.4 Exemple avec une plus grande surdispersion . . . 754
43.5 Modèles de comptage avec une variable binaire . 758
43.6 Données pondérées et plan d’échantillonnage . . 766
43.7 Lectures complémentaires . . . . . . . . . . . . . 768
14
Préface
15
de ces dernières, bien qu’un peu ardue de prime abord, permet
de comprendre le sens des commandes que l’on utilise et de
pleinement exploiter la puissance que R offre en matière de
manipulation de données.
R disposent de nombreuses extensions ou packages (plus de
16 000) et il existe souvent plusieurs manières de procéder pour
arriver au même résultat. En particulier, en matière de mani-
pulation de données, on oppose1 souvent base R qui repose sur 1
Une comparaison des deux syntaxes
les fonctions disponibles en standard dans R, la majorité étant est illustrée par une vignette dédiée
de dplyr.
fournies dans les packages {base}, {utils} ou encore {stats},
qui sont toujours chargés par défaut, et le {tidyverse} qui est
une collection de packages comprenant, entre autres, {dplyr},
{tibble}, {tidyr}, {forcats} ou encore {ggplot2}. Il y a un
débat ouvert, parfois passionné, sur le fait de privilégier l’une ou
l’autre approche, et les avantages et inconvénients de chacune
dépendent de nombreux facteurs, comme la lisibilité du code ou
bien les performances en temps de calcul. Dans ce guide, nous
avons adopté un point de vue pragmatique et utiliserons, le plus
souvent mais pas exclusivement, les fonctions du {tidyverse},
de même que nous avons privilégié d’autres packages, comme
{gtsummary} ou {ggstats} par exemple pour la statistique des-
criptive. Cela ne signifie pas, pour chaque point abordé, qu’il
s’agit de l’unique manière de procéder. Dans certains cas, il
s’agit simplement de préférences personnelles.
Bien qu’il en reprenne de nombreux contenus, ce guide ne se
substitue pas au site analyse-R. Il s’agit plutôt d’une version
complémentaire qui a vocation à être plus structurée et parfois
plus sélective dans les contenus présentés.
En complément, on pourra également se référer aux webin-R,
une série de vidéos avec partage d’écran, librement accessibles
sur YouTube : https://www.youtube.com/c/webinR.
Cette version du guide a utilisé r R.Version()[["version.string"]].
Ce document est généré avec quarto et le code source est dis-
ponible sur GitHub. Pour toute suggestion ou correction, vous
pouvez ouvrir un ticket GitHub. Pour d’autres questions, vous
pouvez utiliser les forums de discussion disponibles en bas de
chaque page sur la version web du guide. Ce document est
régulièrement mis à jour. La dernière version est consultable
sur https://larmarange.github.io/guide-R/.
16
Remerciements
Licence
17
partie I
Bases du langage
18
1 Packages
19
1.1 Installation (CRAN)
install.packages("gtsummary")
remotes::install_cran("gtsummary")
Ĺ Note
1.2 Chargement
library(gtsummary)
20
À partir de là, on peut utiliser les fonctions de l’extension,
consulter leur page d’aide en ligne, accéder aux jeux de don-
nées qu’elle contient, etc.
Alternativement, pour accéder à un objet ou une fonction d’un
package sans avoir à le charger en mémoire, on pourra avoir re-
cours à l’opérateur ::. Ainsi, l’écriture p::f() signifie la fonc-
tion f() du package p. Cette écriture sera notamment utilisée
tout au long de ce guide pour indiquer à quel package appar-
tient telle fonction : remotes::install_cran() indique que la
fonction install_cran() provient du packages {remotes}.
ĺ Important
update.packages()
remove.packages("gtsummary")
21
Ď Installer / Mettre à jour les packages utilisés par un
projet
renv::dependencies() |>
purrr::pluck("Package") |>
unique() |>
remotes::install_cran()
22
Á Sous Windows
remotes::install_github("larmarange/labelled")
1.5 Le tidyverse
• visualisation ({ggplot2})
• manipulation des tableaux de données ({dplyr},
{tidyr})
• import/export de données ({readr}, {readxl}, {haven})
• manipulation de variables ({forcats}, {stringr},
{lubridate})
23
• programmation ({purrr}, {magrittr}, {glue})
install.packages("tidyverse")
24
Figure 1.1: Packages chargés avec library(tidyverse)
25
2 Vecteurs
26
La fonction class() renvoie la nature d’un vecteur tandis que
la fonction typeof() indique la manière dont un vecteur est
stocké de manière interne par R.
x class(x) typeof(x)
3L integer integer
5.3 numeric double
TRUE logical logical
"abc" character character
factor("a") factor integer
as.Date("2020-01-01") Date double
Ď Astuce
27
sexe <- c("h", "f", "h", "f", "f", "f")
sexe
Nous l’avons vu, toutes les valeurs d’un vecteur doivent obliga-
toirement être du même type. Dès lors, si on essaie de combiner
des valeurs de différents types, R essaiera de les convertir au
mieux. Par exemple :
class(x)
[1] "character"
rep(2, 10)
[1] 2 2 2 2 2 2 2 2 2 2
28
rep(c("a", "b"), 3)
seq(1, 10)
[1] 1 2 3 4 5 6 7 8 9 10
seq(5, 17, by = 2)
[1] 5 7 9 11 13 15 17
seq(10, 0)
[1] 10 9 8 7 6 5 4 3 2 1 0
[1] 100 90 80 70 60 50 40 30 20 10
[1] 1.23 1.56 1.89 2.22 2.55 2.88 3.21 3.54 3.87 4.20 4.53 4.86 5.19 5.52
29
1:5
[1] 1 2 3 4 5
24:32
[1] 24 25 26 27 28 29 30 31 32
55:43
[1] 55 54 53 52 51 50 49 48 47 46 45 44 43
length(taille)
[1] 6
length(c("a", "b"))
[1] 2
length(NULL)
[1] 0
30
2.4 Combiner des vecteurs
x <- c(2, 1, 3, 4)
length(x)
[1] 4
y <- c(9, 1, 2, 6, 3, 0)
length(y)
[1] 6
z <- c(x, y)
z
[1] 2 1 3 4 9 1 2 6 3 0
length(z)
[1] 10
sexe <- c(
Michel = "h", Anne = "f",
Dominique = NA, Jean = "h",
31
Claude = NA, Marie = "f"
)
sexe
names(sexe)
32
2.6 Indexation par position
taille
taille[1]
[1] 1.88
taille[1:3]
taille[c(2, 5, 6)]
33
taille[length(taille)]
[1] 1.72
taille[c(5, 1, 4, 3)]
taille[c(-1, -5)]
taille[23:25]
[1] NA NA NA
sexe["Anna"]
Anna
"f"
34
sexe[c("Mary", "Michael", "John")]
sexe[names(sexe) != "Dom"]
sexe
Michael John
"h" "h"
35
urbain <- c(TRUE, TRUE, FALSE, FALSE, FALSE, TRUE)
poids <- c(80, 63, 75, 87, 82, 67)
sexe[urbain]
poids >= 80
36
est remplie et FALSE dans les autres cas. Nous pouvons alors
utiliser ce vecteur logique pour obtenir la taille des participants
pesant 80 kilogrammes ou plus :
37
de cette condition n’est pas toujours TRUE ou FALSE, il
peut aussi être à son tour une valeur manquante.
taille
taille
poids
[1] 80 63 75 87 82 67
38
[1] 80 75 NA
[1] 80 75
v <- 1:5
v
[1] 1 2 3 4 5
v[1] <- 3
v
[1] 3 2 3 4 5
39
Enfin on peut modifier plusieurs éléments d’un seul coup soit en
fournissant un vecteur, soit en profitant du mécanisme de recy-
clage. Les deux commandes suivantes sont ainsi rigoureusement
équivalentes :
length(sexe)
[1] 6
length(sexe)
[1] 7
2.10 En résumé
40
• Les valeurs manquantes sont représentées avec NA.
• Un vecteur peut être nommé, c’est-à-dire qu’un nom tex-
tuel a été associé à chaque élément. Cela peut se faire lors
de sa création ou avec la fonction names().
• L’indexation consiste à extraire certains éléments d’un
vecteur. Pour cela, on indique ce qu’on souhaite extraire
entre crochets ([]) juste après le nom du vecteur. Le type
d’indexation dépend du type d’information transmise.
• S’il s’agit de nombres entiers, c’est l’indexation par posi-
tion : les nombres représentent la position dans le vecteur
des éléments qu’on souhaite extraire. Un nombre négatif
s’interprète comme tous les éléments sauf celui-là.
• Si on indique des chaînes de caractères, c’est l’indexation
par nom : on indique le nom des éléments qu’on souhaite
extraire. Cette forme d’indexation ne fonctionne que si le
vecteur est nommé.
• Si on transmet des valeurs logiques, le plus souvent sous
la forme d’une condition, c’est l’indexation par condition :
TRUE indique les éléments à extraire et FALSE les éléments
à exclure. Il faut être vigilant aux valeurs manquantes (NA)
dans ce cas précis.
• Enfin, il est possible de ne modifier que certains éléments
d’un vecteur en ayant recours à la fois à l’indexation ([])
et à l’assignation (<-).
2.11 webin-R
41
3 Listes
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] "abc"
length(l1)
[1] 2
42
Comme les vecteurs, une liste peut être nommée et les noms
des éléments d’une liste sont accessibles avec names() :
l2 <- list(
minuscules = letters,
majuscules = LETTERS,
mois = month.name
)
l2
$minuscules
[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"
$majuscules
[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"
$mois
[1] "January" "February" "March" "April" "May" "June"
[7] "July" "August" "September" "October" "November" "December"
length(l2)
[1] 3
names(l2)
43
length(l)
[1] 2
Eh bien non ! Elle est de longueur 2 car nous avons créé une
liste composée de deux éléments qui sont eux-mêmes des listes.
Cela est plus lisible si on fait appel à la fonction str() qui
permet de visualiser la structure d’un objet.
str(l)
List of 2
$ :List of 2
..$ : int [1:5] 1 2 3 4 5
..$ : chr "abc"
$ :List of 3
..$ minuscules: chr [1:26] "a" "b" "c" "d" ...
..$ majuscules: chr [1:26] "A" "B" "C" "D" ...
..$ mois : chr [1:12] "January" "February" "March" "April" ...
[1] 5
str(l)
List of 5
$ : int [1:5] 1 2 3 4 5
$ : chr "abc"
$ minuscules: chr [1:26] "a" "b" "c" "d" ...
$ majuscules: chr [1:26] "A" "B" "C" "D" ...
$ mois : chr [1:12] "January" "February" "March" "April" ...
44
Ĺ Note
3.2 Indexation
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] "abc"
$minuscules
[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"
$majuscules
[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"
$mois
[1] "January" "February" "March" "April" "May" "June"
[7] "July" "August" "September" "October" "November" "December"
l[c(1,3,4)]
[[1]]
[1] 1 2 3 4 5
$minuscules
45
[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"
$majuscules
[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"
l[c("majuscules", "minuscules")]
$majuscules
[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"
$minuscules
[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"
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] "abc"
$mois
[1] "January" "February" "March" "April" "May" "June"
[7] "July" "August" "September" "October" "November" "December"
str(l[1])
List of 1
$ : int [1:5] 1 2 3 4 5
46
Supposons que je souhaite calculer la moyenne des valeurs du
premier élément de ma liste. Essayons la commande suivante :
mean(l[1])
[1] NA
str(l[1])
List of 1
$ : int [1:5] 1 2 3 4 5
str(l[[1]])
int [1:5] 1 2 3 4 5
mean(l[[1]])
[1] 3
47
l[["mois"]]
l$mois
l$1
[[1]]
[1] 1 2 3 4 5
[[2]]
[[2]][[1]]
[1] "un" "vecteur" "textuel"
48
$minuscules
[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"
$majuscules
[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"
$mois
[1] "Janvier" "Février" "Mars"
3.3 En résumé
3.4 webin-R
49
4 Tableaux de données
df <- data.frame(
sexe = c("f", "f", "h", "h"),
age = c(52, 31, 29, 35),
blond = c(FALSE, TRUE, TRUE, FALSE)
)
df
50
2 f 31 TRUE
3 h 29 TRUE
4 h 35 FALSE
str(df)
length(df)
[1] 3
names(df)
nrow(df)
[1] 4
ncol(df)
[1] 3
51
dim(df)
[1] 4 3
De plus, tout comme les colonnes ont un nom, il est aussi pos-
sible de nommer les lignes avec row.names() :
4.2 Indexation
df[1]
sexe
Anna f
Mary-Ann f
Michael h
John h
df[[1]]
52
df$sexe
df
df[3, 2]
[1] 29
df["Michael", "age"]
[1] 29
[1] 29
53
df[3, "age"]
[1] 29
df["Michael", 2]
[1] 29
df[1:2,]
df[,c("sexe", "blond")]
sexe blond
Anna f FALSE
Mary-Ann f TRUE
Michael h TRUE
John h FALSE
Á Avertissement
54
df[2, ]
df[, 2]
[1] 52 31 29 35
df[2]
age
Anna 52
Mary-Ann 31
Michael 29
John 35
Ĺ Note
str(df[2, ])
str(df[, 2])
num [1:4] 52 31 29 35
str(df[2])
55
str(df[[2]])
num [1:4] 52 31 29 35
library(questionr)
data(hdv2003)
56
View(hdv2003)
head(hdv2003)
57
3 Ni croyance ni appartenance Aussi important que le reste Equilibre
4 Appartenance sans pratique Moins important que le reste Satisfaction
5 Pratiquant regulier <NA> <NA>
6 Ni croyance ni appartenance Le plus important Equilibre
hard.rock lecture.bd peche.chasse cuisine bricol cinema sport heures.tv
1 Non Non Non Oui Non Non Non 0
2 Non Non Non Non Non Oui Oui 1
3 Non Non Non Non Non Non Oui 0
4 Non Non Non Oui Oui Oui Oui 2
5 Non Non Non Non Non Non Non 3
6 Non Non Non Non Non Oui Oui 2
tail(hdv2003, 2)
library(dplyr)
glimpse(hdv2003)
Rows: 2,000
Columns: 20
$ id <int> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 1~
58
$ age <int> 28, 23, 59, 34, 71, 35, 60, 47, 20, 28, 65, 47, 63, 67, ~
$ sexe <fct> Femme, Femme, Homme, Homme, Femme, Femme, Femme, Homme, ~
$ nivetud <fct> "Enseignement superieur y compris technique superieur", ~
$ poids <dbl> 2634.3982, 9738.3958, 3994.1025, 5731.6615, 4329.0940, 8~
$ occup <fct> "Exerce une profession", "Etudiant, eleve", "Exerce une ~
$ qualif <fct> Employe, NA, Technicien, Technicien, Employe, Employe, O~
$ freres.soeurs <int> 8, 2, 2, 1, 0, 5, 1, 5, 4, 2, 3, 4, 1, 5, 2, 3, 4, 0, 2,~
$ clso <fct> Oui, Oui, Non, Non, Oui, Non, Oui, Non, Oui, Non, Oui, O~
$ relig <fct> Ni croyance ni appartenance, Ni croyance ni appartenance~
$ trav.imp <fct> Peu important, NA, Aussi important que le reste, Moins i~
$ trav.satisf <fct> Insatisfaction, NA, Equilibre, Satisfaction, NA, Equilib~
$ hard.rock <fct> Non, Non, Non, Non, Non, Non, Non, Non, Non, Non, Non, N~
$ lecture.bd <fct> Non, Non, Non, Non, Non, Non, Non, Non, Non, Non, Non, N~
$ peche.chasse <fct> Non, Non, Non, Non, Non, Non, Oui, Oui, Non, Non, Non, N~
$ cuisine <fct> Oui, Non, Non, Oui, Non, Non, Oui, Oui, Non, Non, Oui, N~
$ bricol <fct> Non, Non, Non, Oui, Non, Non, Non, Oui, Non, Non, Oui, O~
$ cinema <fct> Non, Oui, Non, Oui, Non, Oui, Non, Non, Oui, Oui, Oui, N~
$ sport <fct> Non, Oui, Oui, Oui, Non, Oui, Non, Non, Non, Oui, Non, O~
$ heures.tv <dbl> 0.0, 1.0, 0.0, 2.0, 3.0, 2.0, 2.9, 1.0, 2.0, 2.0, 1.0, 0~
library(labelled)
look_for(hdv2003)
59
5 poids — dbl 0
6 occup — fct 0
8 freres.soeurs — int 0
9 clso — fct 0
10 relig — fct 0
13 hard.rock — fct 0
14 lecture.bd — fct 0
15 peche.chasse — fct 0
16 cuisine — fct 0
17 bricol — fct 0
60
18 cinema — fct 0
19 sport — fct 0
20 heures.tv — dbl 5
values
Homme
Femme
N'a jamais fait d'etudes
A arrete ses etudes, avant la derniere ann~
Derniere annee d'etudes primaires
1er cycle
2eme cycle
Enseignement technique ou professionnel co~
Enseignement technique ou professionnel lo~
Enseignement superieur y compris technique~
Oui
Non
Ne sait pas
Pratiquant regulier
Pratiquant occasionnel
Appartenance sans pratique
61
Ni croyance ni appartenance
Rejet
NSP ou NVPR
Le plus important
Aussi important que le reste
Moins important que le reste
Peu important
Satisfaction
Insatisfaction
Equilibre
Non
Oui
Non
Oui
Non
Oui
Non
Oui
Non
Oui
Non
Oui
Non
Oui
look_for(hdv2003, "trav")
62
Equilibre
summary(hdv2003)
id age sexe
Min. : 1.0 Min. :18.00 Homme: 899
1st Qu.: 500.8 1st Qu.:35.00 Femme:1101
Median :1000.5 Median :48.00
Mean :1000.5 Mean :48.16
3rd Qu.:1500.2 3rd Qu.:60.00
Max. :2000.0 Max. :97.00
nivetud poids
Enseignement technique ou professionnel court :463 Min. : 78.08
Enseignement superieur y compris technique superieur:441 1st Qu.: 2221.82
Derniere annee d'etudes primaires :341 Median : 4631.19
1er cycle :204 Mean : 5535.61
2eme cycle :183 3rd Qu.: 7626.53
(Other) :256 Max. :31092.14
NA's :112
occup qualif freres.soeurs
Exerce une profession:1049 Employe :594 Min. : 0.000
Chomeur : 134 Ouvrier qualifie :292 1st Qu.: 1.000
Etudiant, eleve : 94 Cadre :260 Median : 2.000
Retraite : 392 Ouvrier specialise :203 Mean : 3.283
Retire des affaires : 77 Profession intermediaire:160 3rd Qu.: 5.000
Au foyer : 171 (Other) :144 Max. :22.000
Autre inactif : 83 NA's :347
clso relig
Oui : 936 Pratiquant regulier :266
Non :1037 Pratiquant occasionnel :442
63
Ne sait pas: 27 Appartenance sans pratique :760
Ni croyance ni appartenance:399
Rejet : 93
NSP ou NVPR : 40
summary(hdv2003$sexe)
Homme Femme
899 1101
summary(hdv2003$age)
64
4.4 En résumé
4.5 webin-R
65
5 Tibbles
66
fonctions des extensions du tidyverse acceptent des data.frames
en entrée, mais retournent un tibble.
Contrairement aux data frames, les tibbles :
library(tidyverse)
tibble(
x = c(1.2345, 12.345, 123.45, 1234.5, 12345),
y = c("a", "b", "c", "d", "e")
)
# A tibble: 5 x 2
x y
<dbl> <chr>
1 1.23 a
2 12.3 b
3 123. c
4 1234. d
5 12345 e
67
d <- as_tibble(mtcars)
d
# A tibble: 32 x 11
mpg cyl disp hp drat wt qsec vs am gear carb
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 21 6 160 110 3.9 2.88 17.0 0 1 4 4
3 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
7 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
8 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
9 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
10 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
# i 22 more rows
class(d)
d <- as_tibble(rownames_to_column(mtcars))
d
# A tibble: 32 x 12
rowname mpg cyl disp hp drat wt qsec vs am gear carb
<chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 Mazda RX4 21 6 160 110 3.9 2.62 16.5 0 1 4 4
2 Mazda RX4 ~ 21 6 160 110 3.9 2.88 17.0 0 1 4 4
68
3 Datsun 710 22.8 4 108 93 3.85 2.32 18.6 1 1 4 1
4 Hornet 4 D~ 21.4 6 258 110 3.08 3.22 19.4 1 0 3 1
5 Hornet Spo~ 18.7 8 360 175 3.15 3.44 17.0 0 0 3 2
6 Valiant 18.1 6 225 105 2.76 3.46 20.2 1 0 3 1
7 Duster 360 14.3 8 360 245 3.21 3.57 15.8 0 0 3 4
8 Merc 240D 24.4 4 147. 62 3.69 3.19 20 1 0 4 2
9 Merc 230 22.8 4 141. 95 3.92 3.15 22.9 1 0 4 2
10 Merc 280 19.2 6 168. 123 3.92 3.44 18.3 1 0 4 4
# i 22 more rows
as.data.frame(d)
69
25 Pontiac Firebird 19.2 8 400.0 175 3.08 3.845 17.05 0 0 3 2
26 Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
27 Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
28 Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
29 Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
30 Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
31 Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
32 Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
column_to_rownames(as.data.frame(d))
70
Fiat X1-9 27.3 4 79.0 66 4.08 1.935 18.90 1 1 4 1
Porsche 914-2 26.0 4 120.3 91 4.43 2.140 16.70 0 1 5 2
Lotus Europa 30.4 4 95.1 113 3.77 1.513 16.90 1 1 5 2
Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
Ferrari Dino 19.7 6 145.0 175 3.62 2.770 15.50 0 1 5 6
Maserati Bora 15.0 8 301.0 335 3.54 3.570 14.60 0 1 5 8
Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
Ĺ Note
d <- tibble(
g = c(1, 2, 3),
data = list(
tibble(x = 1, y = 2),
tibble(x = 4:5, y = 6:7),
tibble(x = 10)
)
)
d
# A tibble: 3 x 2
g data
<dbl> <list>
1 1 <tibble [1 x 2]>
2 2 <tibble [2 x 2]>
3 3 <tibble [1 x 1]>
71
d$data[[2]]
# A tibble: 2 x 2
x y
<int> <int>
1 4 6
2 5 7
reg <-
iris |>
group_by(Species) |>
nest() |>
mutate(
model = map(
data,
~ lm(Sepal.Length ~ Petal.Length + Petal.Width, data = .)
),
tbl = map(model, gtsummary::tbl_regression)
)
reg
# A tibble: 3 x 4
# Groups: Species [3]
Species data model tbl
<fct> <list> <list> <list>
72
1 setosa <tibble [50 x 4]> <lm> <tbl_rgrs>
2 versicolor <tibble [50 x 4]> <lm> <tbl_rgrs>
3 virginica <tibble [50 x 4]> <lm> <tbl_rgrs>
gtsummary::tbl_merge(
reg$tbl,
tab_spanner = paste0("**", reg$Species, "**")
)
73
6 Attributs
attributes(iris)
$names
[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
$class
[1] "data.frame"
$row.names
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
74
[109] 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
[127] 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
[145] 145 146 147 148 149 150
class(iris)
[1] "data.frame"
names(iris)
$names
[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"
$class
[1] "data.frame"
75
$row.names
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
[19] 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
[37] 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
[55] 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
[73] 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
[91] 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
[109] 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
[127] 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
[145] 145 146 147 148 149 150
$perso
[1] "Des notes personnelles"
attr(iris, "perso")
76
partie II
Manipulation de données
77
7 Le pipe
78
Nous obtenons bien le même résultat, mais la lecture de cette
ligne de code est assez difficile et il n’est pas aisé de bien iden-
tifier à quelle fonction est rattaché chaque argument.
Une amélioration possible serait d’effectuer des retours à la
ligne avec une indentation adéquate pour rendre cela plus li-
sible.
message(
paste0(
"La moyenne est de ",
format(
round(
mean(v),
digits = 1),
decimal.mark = ","
),
"."
)
)
79
placeholder doit impérativement être transmis à un argument
nommé !
Tout cela semble encore un peu abstrait ? Reprenons notre
exemple précédent et réécrivons le code avec le pipe.
v |>
mean() |>
round(digits = 1) |>
format(decimal.mark = ",") |>
paste0("La moyenne est de ", m = _, ".") |>
message()
80
library(magrittr)
v %>%
mean() %>%
round(digits = 1) %>%
format(decimal.mark = ",") %>%
paste0("La moyenne est de ", ., ".") %>%
message()
81
7.4 Accéder à un élément avec
purrr::pluck() et purrr::chuck()
iris |>
purrr::pluck("Petal.Width") |>
mean()
[1] 1.199333
mean(iris$Petal.Width)
[1] 1.199333
[1] "b"
82
v[2]
[1] "b"
iris |>
purrr::pluck("Sepal.Width", 3)
[1] 3.2
iris |>
purrr::pluck("Sepal.Width") |>
purrr::pluck(3)
[1] 3.2
iris[["Sepal.Width"]][3]
[1] 3.2
NULL
Error in `purrr::chuck()`:
! Can't find name `inconnu` in vector.
83
v |> purrr::pluck(10)
NULL
v |> purrr::chuck(10)
Error in `purrr::chuck()`:
! Index 1 exceeds the length of plucked object (10 > 4).
84
8 dplyr
library(nycflights13)
## Chargement des trois tables du jeu de données
data(flights)
data(airports)
85
data(airlines)
8.1.1 filter()
filter(flights, month == 1)
# A tibble: 27,004 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# i 26,994 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
86
flights |> filter(month == 1)
# A tibble: 27,004 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# i 26,994 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
flights |>
filter(dep_delay >= 10 & dep_delay <= 15)
# A tibble: 14,919 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 611 600 11 945 931
2 2013 1 1 623 610 13 920 915
3 2013 1 1 743 730 13 1107 1100
4 2013 1 1 743 730 13 1059 1056
5 2013 1 1 851 840 11 1215 1206
6 2013 1 1 912 900 12 1241 1220
7 2013 1 1 914 900 14 1058 1043
8 2013 1 1 920 905 15 1039 1025
9 2013 1 1 1011 1001 10 1133 1128
10 2013 1 1 1112 1100 12 1440 1438
87
# i 14,909 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
flights |>
filter(dep_delay >= 10, dep_delay <= 15)
flights |>
filter(distance == max(distance))
# A tibble: 342 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 857 900 -3 1516 1530
2 2013 1 2 909 900 9 1525 1530
3 2013 1 3 914 900 14 1504 1530
4 2013 1 4 900 900 0 1516 1530
5 2013 1 5 858 900 -2 1519 1530
6 2013 1 6 1019 900 79 1558 1530
7 2013 1 7 1042 900 102 1620 1530
8 2013 1 8 901 900 1 1504 1530
9 2013 1 9 641 900 1301 1242 1530
10 2013 1 10 859 900 -1 1449 1530
# i 332 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
88
Ď Évaluation contextuelle
m <- 2
flights |>
filter(month == m)
# A tibble: 24,951 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 2 1 456 500 -4 652 648
2 2013 2 1 520 525 -5 816 820
3 2013 2 1 527 530 -3 837 829
4 2013 2 1 532 540 -8 1007 1017
5 2013 2 1 540 540 0 859 850
6 2013 2 1 552 600 -8 714 715
7 2013 2 1 552 600 -8 919 910
8 2013 2 1 552 600 -8 655 709
9 2013 2 1 553 600 -7 833 815
10 2013 2 1 553 600 -7 821 825
# i 24,941 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
89
priorité sur les objets du même nom dans l’environnement.
Dans l’exemple ci-dessous, le résultat obtenu n’est pas ce-
lui voulu. Il est interprété comme sélectionner toutes les
lignes où la colonne mois est égale à elle-même et donc
cela sélectionne toutes les lignes du tableau.
month <- 3
flights |>
filter(month == month)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# i 336,766 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
month <- 3
flights |>
filter(.data$month == .env$month)
# A tibble: 28,834 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
90
1 2013 3 1 4 2159 125 318 56
2 2013 3 1 50 2358 52 526 438
3 2013 3 1 117 2245 152 223 2354
4 2013 3 1 454 500 -6 633 648
5 2013 3 1 505 515 -10 746 810
6 2013 3 1 521 530 -9 813 827
7 2013 3 1 537 540 -3 856 850
8 2013 3 1 541 545 -4 1014 1023
9 2013 3 1 549 600 -11 639 703
10 2013 3 1 550 600 -10 747 801
# i 28,824 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.1.2 slice()
airports |>
slice(345)
# A tibble: 1 x 8
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 CYF Chefornak Airport 60.1 -164. 40 -9 A America/Anchorage
airports |>
slice(1:5)
# A tibble: 5 x 8
91
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/New~
2 06A Moton Field Municipal Airport 32.5 -85.7 264 -6 A America/Chi~
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/Chi~
4 06N Randall Airport 41.4 -74.4 523 -5 A America/New~
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/New~
8.1.3 arrange()
flights |>
arrange(dep_delay)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 12 7 2040 2123 -43 40 2352
2 2013 2 3 2022 2055 -33 2240 2338
3 2013 11 10 1408 1440 -32 1549 1559
4 2013 1 11 1900 1930 -30 2233 2243
5 2013 1 29 1703 1730 -27 1947 1957
6 2013 8 9 729 755 -26 1002 955
7 2013 10 23 1907 1932 -25 2143 2143
8 2013 3 30 2030 2055 -25 2213 2250
9 2013 3 2 1431 1455 -24 1601 1631
10 2013 5 5 934 958 -24 1225 1309
# i 336,766 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
92
flights |>
arrange(month, dep_delay)
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 11 1900 1930 -30 2233 2243
2 2013 1 29 1703 1730 -27 1947 1957
3 2013 1 12 1354 1416 -22 1606 1650
4 2013 1 21 2137 2159 -22 2232 2316
5 2013 1 20 704 725 -21 1025 1035
6 2013 1 12 2050 2110 -20 2310 2355
7 2013 1 12 2134 2154 -20 4 50
8 2013 1 14 2050 2110 -20 2329 2355
9 2013 1 4 2140 2159 -19 2241 2316
10 2013 1 11 1947 2005 -18 2209 2230
# i 336,766 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
flights |>
arrange(desc(dep_delay))
# A tibble: 336,776 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
4 2013 9 20 1139 1845 1014 1457 2210
5 2013 7 22 845 1600 1005 1044 1815
6 2013 4 10 1100 1900 960 1342 2211
7 2013 3 17 2321 810 911 135 1020
8 2013 6 27 959 1900 899 1236 2226
9 2013 7 22 2257 759 898 121 1026
93
10 2013 12 5 756 1700 896 1058 2020
# i 336,766 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
flights |>
arrange(desc(dep_delay)) |>
slice(1:3)
# A tibble: 3 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.1.4 slice_sample()
airports |>
slice_sample(n = 5)
# A tibble: 5 x 8
faa name lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 EGV Eagle River 45.9 -89.3 1642 -6 A America/Chica~
94
2 RID Richmond Municipal Airport 39.8 -84.8 1140 -5 U America/New_Y~
3 EGA Eagle County Airport 39.6 -107. 6548 -7 U America/Denver
4 YKN Chan Gurney 42.9 -97.4 1200 -6 A America/Chica~
5 FWA Fort Wayne 41.0 -85.2 815 -5 A America/New_Y~
flights |>
slice_sample(prop = .1)
# A tibble: 33,677 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 13 1828 1705 83 2037 1905
2 2013 12 9 1013 1000 13 1320 1242
3 2013 6 8 1738 1655 43 2023 2005
4 2013 12 24 1518 1520 -2 1648 1700
5 2013 11 21 625 635 -10 808 812
6 2013 4 24 1858 1844 14 2205 2114
7 2013 7 6 654 659 -5 852 909
8 2013 9 15 1922 1925 -3 2212 2248
9 2013 6 17 935 930 5 1036 1042
10 2013 5 28 1356 1359 -3 1542 1554
# i 33,667 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.1.5 distinct()
95
flights |>
select(day, month) |>
distinct()
# A tibble: 365 x 2
day month
<int> <int>
1 1 1
2 2 1
3 3 1
4 4 1
5 5 1
6 6 1
7 7 1
8 8 1
9 9 1
10 10 1
# i 355 more rows
flights |>
distinct(month, day)
# A tibble: 365 x 2
month day
<int> <int>
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
6 1 6
7 1 7
8 1 8
9 1 9
96
10 1 10
# i 355 more rows
flights |>
distinct(month, day, .keep_all = TRUE)
# A tibble: 365 x 19
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 2 42 2359 43 518 442
3 2013 1 3 32 2359 33 504 442
4 2013 1 4 25 2359 26 505 442
5 2013 1 5 14 2359 15 503 445
6 2013 1 6 16 2359 17 451 442
7 2013 1 7 49 2359 50 531 444
8 2013 1 8 454 500 -6 625 648
9 2013 1 9 2 2359 3 432 444
10 2013 1 10 3 2359 4 426 437
# i 355 more rows
# i 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>
8.2.1 select()
airports |>
select(lat, lon)
97
# A tibble: 1,458 x 2
lat lon
<dbl> <dbl>
1 41.1 -80.6
2 32.5 -85.7
3 42.0 -88.1
4 41.4 -74.4
5 31.1 -81.4
6 36.4 -82.2
7 41.5 -84.5
8 42.9 -76.8
9 39.8 -76.6
10 48.1 -123.
# i 1,448 more rows
airports |>
select(-lat, -lon)
# A tibble: 1,458 x 6
faa name alt tz dst tzone
<chr> <chr> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 1044 -5 A America/New_York
2 06A Moton Field Municipal Airport 264 -6 A America/Chicago
3 06C Schaumburg Regional 801 -6 A America/Chicago
4 06N Randall Airport 523 -5 A America/New_York
5 09J Jekyll Island Airport 11 -5 A America/New_York
6 0A9 Elizabethton Municipal Airport 1593 -5 A America/New_York
7 0G6 Williams County Airport 730 -5 A America/New_York
8 0G7 Finger Lakes Regional Airport 492 -5 A America/New_York
9 0P2 Shoestring Aviation Airfield 1000 -5 U America/New_York
10 0S9 Jefferson County Intl 108 -8 A America/Los_Angeles
# i 1,448 more rows
98
dplyr::contains() ou dplyr::matches() permettent
d’exprimer des conditions sur les noms de variables :
flights |>
select(starts_with("dep_"))
# A tibble: 336,776 x 2
dep_time dep_delay
<int> <dbl>
1 517 2
2 533 4
3 542 2
4 544 -1
5 554 -6
6 554 -4
7 555 -5
8 557 -3
9 557 -3
10 558 -2
# i 336,766 more rows
# A tibble: 336,776 x 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
99
10 2013 1 1
# i 336,766 more rows
flights |>
select(all_of(c("year", "month", "day")))
# A tibble: 336,776 x 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# i 336,766 more rows
flights |>
select(all_of(c("century", "year", "month", "day")))
Error in `all_of()`:
! Can't subset columns that don't exist.
x Column `century` doesn't exist.
100
flights |>
select(any_of(c("century", "year", "month", "day")))
# A tibble: 336,776 x 3
year month day
<int> <int> <int>
1 2013 1 1
2 2013 1 1
3 2013 1 1
4 2013 1 1
5 2013 1 1
6 2013 1 1
7 2013 1 1
8 2013 1 1
9 2013 1 1
10 2013 1 1
# i 336,766 more rows
flights |>
select(where(is.character))
# A tibble: 336,776 x 4
carrier tailnum origin dest
<chr> <chr> <chr> <chr>
1 UA N14228 EWR IAH
2 UA N24211 LGA IAH
3 AA N619AA JFK MIA
4 B6 N804JB JFK BQN
5 DL N668DN LGA ATL
6 UA N39463 EWR ORD
7 B6 N516JB EWR FLL
8 EV N829AS LGA IAD
9 B6 N593JB JFK MCO
10 AA N3ALAA LGA ORD
# i 336,766 more rows
101
dplyr::select() peut être utilisée pour réordonner les co-
lonnes d’une table en utilisant la fonction dplyr::everything(),
qui sélectionne l’ensemble des colonnes non encore sélection-
nées. Ainsi, si l’on souhaite faire passer la colonne name en
première position de la table airports, on peut faire :
airports |>
select(name, everything())
# A tibble: 1,458 x 8
name faa lat lon alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 Lansdowne Airport 04G 41.1 -80.6 1044 -5 A America/~
2 Moton Field Municipal Airport 06A 32.5 -85.7 264 -6 A America/~
3 Schaumburg Regional 06C 42.0 -88.1 801 -6 A America/~
4 Randall Airport 06N 41.4 -74.4 523 -5 A America/~
5 Jekyll Island Airport 09J 31.1 -81.4 11 -5 A America/~
6 Elizabethton Municipal Airport 0A9 36.4 -82.2 1593 -5 A America/~
7 Williams County Airport 0G6 41.5 -84.5 730 -5 A America/~
8 Finger Lakes Regional Airport 0G7 42.9 -76.8 492 -5 A America/~
9 Shoestring Aviation Airfield 0P2 39.8 -76.6 1000 -5 U America/~
10 Jefferson County Intl 0S9 48.1 -123. 108 -8 A America/~
# i 1,448 more rows
8.2.2 relocate()
airports |>
relocate(lon, lat, name)
# A tibble: 1,458 x 8
lon lat name faa alt tz dst tzone
<dbl> <dbl> <chr> <chr> <dbl> <dbl> <chr> <chr>
1 -80.6 41.1 Lansdowne Airport 04G 1044 -5 A America/~
2 -85.7 32.5 Moton Field Municipal Airport 06A 264 -6 A America/~
102
3 -88.1 42.0 Schaumburg Regional 06C 801 -6 A America/~
4 -74.4 41.4 Randall Airport 06N 523 -5 A America/~
5 -81.4 31.1 Jekyll Island Airport 09J 11 -5 A America/~
6 -82.2 36.4 Elizabethton Municipal Airport 0A9 1593 -5 A America/~
7 -84.5 41.5 Williams County Airport 0G6 730 -5 A America/~
8 -76.8 42.9 Finger Lakes Regional Airport 0G7 492 -5 A America/~
9 -76.6 39.8 Shoestring Aviation Airfield 0P2 1000 -5 U America/~
10 -123. 48.1 Jefferson County Intl 0S9 108 -8 A America/~
# i 1,448 more rows
8.2.3 rename()
airports |>
rename(longitude = lon, latitude = lat)
# A tibble: 1,458 x 8
faa name latitude longitude alt tz dst tzone
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A Amer~
2 06A Moton Field Municipal Airpo~ 32.5 -85.7 264 -6 A Amer~
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A Amer~
4 06N Randall Airport 41.4 -74.4 523 -5 A Amer~
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A Amer~
6 0A9 Elizabethton Municipal Airp~ 36.4 -82.2 1593 -5 A Amer~
7 0G6 Williams County Airport 41.5 -84.5 730 -5 A Amer~
8 0G7 Finger Lakes Regional Airpo~ 42.9 -76.8 492 -5 A Amer~
9 0P2 Shoestring Aviation Airfield 39.8 -76.6 1000 -5 U Amer~
10 0S9 Jefferson County Intl 48.1 -123. 108 -8 A Amer~
# i 1,448 more rows
103
flights |>
rename(
"retard départ" = dep_delay,
"retard arrivée" = arr_delay
) |>
select(`retard départ`, `retard arrivée`)
# A tibble: 336,776 x 2
`retard départ` `retard arrivée`
<dbl> <dbl>
1 2 11
2 4 20
3 2 33
4 -1 -18
5 -6 -25
6 -4 12
7 -5 19
8 -3 -14
9 -3 -8
10 -2 8
# i 336,766 more rows
8.2.4 rename_with()
airports |>
rename_with(toupper)
# A tibble: 1,458 x 8
FAA NAME LAT LON ALT TZ DST TZONE
<chr> <chr> <dbl> <dbl> <dbl> <dbl> <chr> <chr>
1 04G Lansdowne Airport 41.1 -80.6 1044 -5 A America/~
2 06A Moton Field Municipal Airport 32.5 -85.7 264 -6 A America/~
3 06C Schaumburg Regional 42.0 -88.1 801 -6 A America/~
104
4 06N Randall Airport 41.4 -74.4 523 -5 A America/~
5 09J Jekyll Island Airport 31.1 -81.4 11 -5 A America/~
6 0A9 Elizabethton Municipal Airport 36.4 -82.2 1593 -5 A America/~
7 0G6 Williams County Airport 41.5 -84.5 730 -5 A America/~
8 0G7 Finger Lakes Regional Airport 42.9 -76.8 492 -5 A America/~
9 0P2 Shoestring Aviation Airfield 39.8 -76.6 1000 -5 U America/~
10 0S9 Jefferson County Intl 48.1 -123. 108 -8 A America/~
# i 1,448 more rows
airports |>
pull(alt) |>
mean()
[1] 1001.416
Ĺ Note
8.2.6 mutate()
105
Par exemple, la table airports contient l’altitude de l’aéroport
en pieds. Si l’on veut créer une nouvelle variable alt_m avec
l’altitude en mètres, on peut faire :
airports <-
airports |>
mutate(alt_m = alt / 3.2808)
flights <-
flights |>
mutate(
distance_km = distance / 0.62137,
vitesse = distance_km / air_time * 60
)
8.3.1 group_by()
flights |>
group_by(month)
# A tibble: 336,776 x 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
106
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# i 336,766 more rows
# i 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
flights |>
group_by(month) |>
slice(1)
# A tibble: 12 x 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 2 1 456 500 -4 652 648
3 2013 3 1 4 2159 125 318 56
4 2013 4 1 454 500 -6 636 640
5 2013 5 1 9 1655 434 308 2020
107
6 2013 6 1 2 2359 3 341 350
7 2013 7 1 1 2029 212 236 2359
8 2013 8 1 12 2130 162 257 14
9 2013 9 1 9 2359 10 343 340
10 2013 10 1 447 500 -13 614 648
11 2013 11 1 5 2359 6 352 345
12 2013 12 1 13 2359 14 446 445
# i 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
flights |>
group_by(month) |>
mutate(mean_delay_month = mean(dep_delay, na.rm = TRUE))
# A tibble: 336,776 x 22
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 1 517 515 2 830 819
2 2013 1 1 533 529 4 850 830
3 2013 1 1 542 540 2 923 850
4 2013 1 1 544 545 -1 1004 1022
5 2013 1 1 554 600 -6 812 837
6 2013 1 1 554 558 -4 740 728
7 2013 1 1 555 600 -5 913 854
8 2013 1 1 557 600 -3 709 723
9 2013 1 1 557 600 -3 838 846
10 2013 1 1 558 600 -2 753 745
# i 336,766 more rows
# i 14 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
108
# vitesse <dbl>, mean_delay_month <dbl>
flights |>
group_by(month) |>
filter(dep_delay == max(dep_delay, na.rm = TRUE))
# A tibble: 12 x 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 10 14 2042 900 702 2255 1127
3 2013 11 3 603 1645 798 829 1913
4 2013 12 5 756 1700 896 1058 2020
5 2013 2 10 2243 830 853 100 1106
6 2013 3 17 2321 810 911 135 1020
7 2013 4 10 1100 1900 960 1342 2211
8 2013 5 3 1133 2055 878 1250 2215
9 2013 6 15 1432 1935 1137 1607 2120
10 2013 7 22 845 1600 1005 1044 1815
11 2013 8 8 2334 1454 520 120 1710
12 2013 9 20 1139 1845 1014 1457 2210
# i 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
109
On peut voir la différence en comparant les deux résultats sui-
vants :
flights |>
group_by(month) |>
arrange(desc(dep_delay))
# A tibble: 336,776 x 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 6 15 1432 1935 1137 1607 2120
3 2013 1 10 1121 1635 1126 1239 1810
4 2013 9 20 1139 1845 1014 1457 2210
5 2013 7 22 845 1600 1005 1044 1815
6 2013 4 10 1100 1900 960 1342 2211
7 2013 3 17 2321 810 911 135 1020
8 2013 6 27 959 1900 899 1236 2226
9 2013 7 22 2257 759 898 121 1026
10 2013 12 5 756 1700 896 1058 2020
# i 336,766 more rows
# i 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
flights |>
group_by(month) |>
arrange(desc(dep_delay), .by_group = TRUE)
# A tibble: 336,776 x 21
# Groups: month [12]
year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
<int> <int> <int> <int> <int> <dbl> <int> <int>
1 2013 1 9 641 900 1301 1242 1530
2 2013 1 10 1121 1635 1126 1239 1810
3 2013 1 1 848 1835 853 1001 1950
4 2013 1 13 1809 810 599 2054 1042
110
5 2013 1 16 1622 800 502 1911 1054
6 2013 1 23 1551 753 478 1812 1006
7 2013 1 10 1525 900 385 1713 1039
8 2013 1 1 2343 1724 379 314 1938
9 2013 1 2 2131 1512 379 2340 1741
10 2013 1 7 2021 1415 366 2332 1724
# i 336,766 more rows
# i 13 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
# tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
# hour <dbl>, minute <dbl>, time_hour <dttm>, distance_km <dbl>,
# vitesse <dbl>
8.3.2 summarise()
flights |>
summarise(
retard_dep = mean(dep_delay, na.rm=TRUE),
retard_arr = mean(arr_delay, na.rm=TRUE)
)
# A tibble: 1 x 2
retard_dep retard_arr
<dbl> <dbl>
1 12.6 6.90
111
flights |>
group_by(month) |>
summarise(
max_delay = max(dep_delay, na.rm=TRUE),
min_delay = min(dep_delay, na.rm=TRUE),
mean_delay = mean(dep_delay, na.rm=TRUE)
)
# A tibble: 12 x 4
month max_delay min_delay mean_delay
<int> <dbl> <dbl> <dbl>
1 1 1301 -30 10.0
2 2 853 -33 10.8
3 3 911 -25 13.2
4 4 960 -21 13.9
5 5 878 -24 13.0
6 6 1137 -21 20.8
7 7 1005 -22 21.7
8 8 520 -26 12.6
9 9 1014 -24 6.72
10 10 702 -25 6.24
11 11 798 -32 5.44
12 12 896 -43 16.6
flights |>
group_by(dest) |>
summarise(n = n())
# A tibble: 105 x 2
dest n
<chr> <int>
1 ABQ 254
2 ACK 265
3 ALB 439
112
4 ANC 8
5 ATL 17215
6 AUS 2439
7 AVL 275
8 BDL 443
9 BGR 375
10 BHM 297
# i 95 more rows
8.3.3 count()
flights |>
count(dest)
# A tibble: 105 x 2
dest n
<chr> <int>
1 ABQ 254
2 ACK 265
3 ALB 439
4 ANC 8
5 ATL 17215
6 AUS 2439
7 AVL 275
8 BDL 443
9 BGR 375
10 BHM 297
# i 95 more rows
113
8.3.4 Grouper selon plusieurs variables
flights |>
group_by(month, dest) |>
summarise(nb = n()) |>
arrange(desc(nb))
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 x 3
# Groups: month [12]
month dest nb
<int> <chr> <int>
1 8 ORD 1604
2 10 ORD 1604
3 5 ORD 1582
4 9 ORD 1582
5 7 ORD 1573
6 6 ORD 1547
7 7 ATL 1511
8 8 ATL 1507
9 8 LAX 1505
10 7 LAX 1500
# i 1,103 more rows
flights |>
count(origin, dest) |>
arrange(desc(n))
# A tibble: 224 x 3
origin dest n
<chr> <chr> <int>
114
1 JFK LAX 11262
2 LGA ATL 10263
3 LGA ORD 8857
4 JFK SFO 8204
5 LGA CLT 6168
6 EWR ORD 6100
7 JFK BOS 5898
8 LGA MIA 5781
9 JFK MCO 5464
10 EWR BOS 5327
# i 214 more rows
flights |>
group_by(month, origin, dest) |>
summarise(nb = n()) |>
group_by(month) |>
filter(nb == max(nb))
`summarise()` has grouped output by 'month', 'origin'. You can override using
the `.groups` argument.
# A tibble: 12 x 4
# Groups: month [12]
month origin dest nb
<int> <chr> <chr> <int>
1 1 JFK LAX 937
2 2 JFK LAX 834
3 3 JFK LAX 960
115
4 4 JFK LAX 935
5 5 JFK LAX 960
6 6 JFK LAX 928
7 7 JFK LAX 985
8 8 JFK LAX 979
9 9 JFK LAX 925
10 10 JFK LAX 965
11 11 JFK LAX 907
12 12 JFK LAX 947
`summarise()` has grouped output by 'month', 'origin'. You can override using
the `.groups` argument.
# A tibble: 2,313 x 4
# Groups: month, origin [36]
month origin dest nb
<int> <chr> <chr> <int>
1 1 EWR ALB 64
2 1 EWR ATL 362
3 1 EWR AUS 51
4 1 EWR AVL 2
5 1 EWR BDL 37
6 1 EWR BNA 111
7 1 EWR BOS 430
8 1 EWR BQN 31
9 1 EWR BTV 100
10 1 EWR BUF 119
# i 2,303 more rows
116
Cela peut permettre d’enchaîner les opérations groupées. Dans
l’exemple suivant, on calcule le pourcentage des trajets pour
chaque destination par rapport à tous les trajets du mois :
flights |>
group_by(month, dest) |>
summarise(nb = n()) |>
mutate(pourcentage = nb / sum(nb) * 100)
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 x 4
# Groups: month [12]
month dest nb pourcentage
<int> <chr> <int> <dbl>
1 1 ALB 64 0.237
2 1 ATL 1396 5.17
3 1 AUS 169 0.626
4 1 AVL 2 0.00741
5 1 BDL 37 0.137
6 1 BHM 25 0.0926
7 1 BNA 399 1.48
8 1 BOS 1245 4.61
9 1 BQN 93 0.344
10 1 BTV 223 0.826
# i 1,103 more rows
flights |>
group_by(month, dest) |>
summarise(nb = n()) |>
ungroup() |>
mutate(pourcentage = nb / sum(nb) * 100)
117
`summarise()` has grouped output by 'month'. You can override using the
`.groups` argument.
# A tibble: 1,113 x 4
month dest nb pourcentage
<int> <chr> <int> <dbl>
1 1 ALB 64 0.0190
2 1 ATL 1396 0.415
3 1 AUS 169 0.0502
4 1 AVL 2 0.000594
5 1 BDL 37 0.0110
6 1 BHM 25 0.00742
7 1 BNA 399 0.118
8 1 BOS 1245 0.370
9 1 BQN 93 0.0276
10 1 BTV 223 0.0662
# i 1,103 more rows
flights |>
count(month, dest)
# A tibble: 1,113 x 3
month dest n
<int> <chr> <int>
1 1 ALB 64
2 1 ATL 1396
3 1 AUS 169
4 1 AVL 2
5 1 BDL 37
6 1 BHM 25
7 1 BNA 399
8 1 BOS 1245
9 1 BQN 93
10 1 BTV 223
# i 1,103 more rows
118
8.4 Cheatsheet
8.5 webin-R
119
9 Facteurs et forcats
Ĺ Note
120
[1] nord sud sud est est est
Levels: est nord sud
x |>
factor(levels = c("nord", "est", "sud", "ouest"))
Si une valeur observée dans les données n’est pas indiqué dans
levels, elle sera silencieusement convertie en valeur manquante
(NA).
x |>
factor(levels = c("nord", "sud"))
x |>
readr::parse_factor(levels = c("nord", "sud"))
121
[1] nord sud sud <NA> <NA> <NA>
attr(,"problems")
# A tibble: 3 x 4
row col expected actual
<int> <int> <chr> <chr>
1 4 NA value in level set est
2 5 NA value in level set est
3 6 NA value in level set est
Levels: nord sud
f <- factor(x)
levels(f)
class(f)
[1] "factor"
122
typeof(f)
[1] "integer"
as.integer(f)
[1] 2 3 3 1 1 1
as.character(f)
library(tidyverse)
data("hdv2003", package = "questionr")
hdv2003$qualif |>
levels()
123
hdv2003$qualif |>
questionr::freq()
n % val%
Ouvrier specialise 203 10.2 12.3
Ouvrier qualifie 292 14.6 17.7
Technicien 86 4.3 5.2
Profession intermediaire 160 8.0 9.7
Cadre 260 13.0 15.7
Employe 594 29.7 35.9
Autre 58 2.9 3.5
NA 347 17.3 NA
hdv2003$qualif |>
fct_rev() |>
questionr::freq()
n % val%
Autre 58 2.9 3.5
Employe 594 29.7 35.9
Cadre 260 13.0 15.7
Profession intermediaire 160 8.0 9.7
Technicien 86 4.3 5.2
Ouvrier qualifie 292 14.6 17.7
Ouvrier specialise 203 10.2 12.3
NA 347 17.3 NA
124
hdv2003$qualif |>
fct_relevel("Cadre", "Autre", "Technicien", "Employe") |>
questionr::freq()
n % val%
Cadre 260 13.0 15.7
Autre 58 2.9 3.5
Technicien 86 4.3 5.2
Employe 594 29.7 35.9
Ouvrier specialise 203 10.2 12.3
Ouvrier qualifie 292 14.6 17.7
Profession intermediaire 160 8.0 9.7
NA 347 17.3 NA
hdv2003$qualif |>
fct_infreq() |>
questionr::freq()
n % val%
Employe 594 29.7 35.9
Ouvrier qualifie 292 14.6 17.7
Cadre 260 13.0 15.7
Ouvrier specialise 203 10.2 12.3
Profession intermediaire 160 8.0 9.7
Technicien 86 4.3 5.2
Autre 58 2.9 3.5
NA 347 17.3 NA
hdv2003$qualif |>
fct_infreq() |>
fct_rev() |>
125
questionr::freq()
n % val%
Autre 58 2.9 3.5
Technicien 86 4.3 5.2
Profession intermediaire 160 8.0 9.7
Ouvrier specialise 203 10.2 12.3
Cadre 260 13.0 15.7
Ouvrier qualifie 292 14.6 17.7
Employe 594 29.7 35.9
NA 347 17.3 NA
[1] c a d b a c
Levels: a b c d
fct_inorder(v)
[1] c a d b a c
Levels: c a d b
hdv2003$qualif_tri_age <-
hdv2003$qualif |>
fct_reorder(hdv2003$age, .fun = mean)
hdv2003 |>
dplyr::group_by(qualif_tri_age) |>
126
dplyr::summarise(age_moyen = mean(age))
# A tibble: 8 x 2
qualif_tri_age age_moyen
<fct> <dbl>
1 Technicien 45.9
2 Employe 46.7
3 Autre 47.0
4 Ouvrier specialise 48.9
5 Profession intermediaire 49.1
6 Cadre 49.7
7 Ouvrier qualifie 50.0
8 <NA> 47.9
Ď Astuce
127
Une démonstration en vidéo de cet add-in est disponible
dans le webin-R #05 (recoder des variables) sur [You-
Tube](https://youtu.be/CokvTbtWdwc?t=3934).
https://youtu.be/CokvTbtWdwc
hdv2003$sexe |>
questionr::freq()
n % val%
Homme 899 45 45
Femme 1101 55 55
hdv2003$sexe <-
hdv2003$sexe |>
fct_recode(f = "Femme", m = "Homme")
hdv2003$sexe |>
questionr::freq()
n % val%
m 899 45 45
f 1101 55 55
hdv2003$nivetud |>
questionr::freq()
128
n % val%
N'a jamais fait d'etudes 39 2.0 2.1
A arrete ses etudes, avant la derniere annee d'etudes primaires 86 4.3 4.6
Derniere annee d'etudes primaires 341 17.0 18.1
1er cycle 204 10.2 10.8
2eme cycle 183 9.2 9.7
Enseignement technique ou professionnel court 463 23.2 24.5
Enseignement technique ou professionnel long 131 6.6 6.9
Enseignement superieur y compris technique superieur 441 22.0 23.4
NA 112 5.6 NA
hdv2003$instruction <-
hdv2003$nivetud |>
fct_recode(
"primaire" = "N'a jamais fait d'etudes",
"primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"primaire" = "Derniere annee d'etudes primaires",
"secondaire" = "1er cycle",
"secondaire" = "2eme cycle",
"technique/professionnel" = "Enseignement technique ou professionnel court",
"technique/professionnel" = "Enseignement technique ou professionnel long",
"supérieur" = "Enseignement superieur y compris technique superieur"
)
hdv2003$instruction |>
questionr::freq()
n % val%
primaire 466 23.3 24.7
secondaire 387 19.4 20.5
technique/professionnel 594 29.7 31.5
supérieur 441 22.0 23.4
NA 112 5.6 NA
Ď Interface graphique
129
générer ensuite le code R correspondant au recodage indi-
qué.
Pour utiliser cette interface, sous RStudio vous pouvez
aller dans le menu Addins (présent dans la barre d’outils
principale) puis choisir Levels recoding. Sinon, vous pouvez
lancer dans la console la fonction questionr::irec() en
lui passant comme paramètre la variable à recoder.
Ď Astuce
130
hdv2003$instruction <-
hdv2003$nivetud |>
fct_collapse(
"primaire" = c(
"N'a jamais fait d'etudes",
"A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Derniere annee d'etudes primaires"
),
"secondaire" = c(
"1er cycle",
"2eme cycle"
),
"technique/professionnel" = c(
"Enseignement technique ou professionnel court",
"Enseignement technique ou professionnel long"
),
"supérieur" = "Enseignement superieur y compris technique superieur"
)
n % val%
primaire 466 23.3 23.3
secondaire 387 19.4 19.4
technique/professionnel 594 29.7 29.7
supérieur 441 22.0 22.0
(manquant) 112 5.6 5.6
131
hdv2003$qualif |>
questionr::freq()
n % val%
Ouvrier specialise 203 10.2 12.3
Ouvrier qualifie 292 14.6 17.7
Technicien 86 4.3 5.2
Profession intermediaire 160 8.0 9.7
Cadre 260 13.0 15.7
Employe 594 29.7 35.9
Autre 58 2.9 3.5
NA 347 17.3 NA
hdv2003$qualif |>
fct_other(keep = c("Technicien", "Cadre", "Employe")) |>
questionr::freq()
n % val%
Technicien 86 4.3 5.2
Cadre 260 13.0 15.7
Employe 594 29.7 35.9
Other 713 35.6 43.1
NA 347 17.3 NA
hdv2003$qualif |>
fct_lump_n(n = 4, other_level = "Autres") |>
questionr::freq()
n % val%
Ouvrier specialise 203 10.2 12.3
Ouvrier qualifie 292 14.6 17.7
Cadre 260 13.0 15.7
Employe 594 29.7 35.9
132
Autres 304 15.2 18.4
NA 347 17.3 NA
hdv2003$qualif |>
fct_lump_min(min = 200, other_level = "Autres") |>
questionr::freq()
n % val%
Ouvrier specialise 203 10.2 12.3
Ouvrier qualifie 292 14.6 17.7
Cadre 260 13.0 15.7
Employe 594 29.7 35.9
Autres 304 15.2 18.4
NA 347 17.3 NA
v <- factor(
c("a", "a", "b", "a"),
levels = c("a", "b", "c")
)
questionr::freq(v)
n % val%
a 3 75 75
b 1 25 25
c 0 0 0
133
[1] a a b a
Levels: a b c
v |> fct_drop()
[1] a a b a
Levels: a b
[1] a a b a
Levels: a b c
[1] a a b a
Levels: a b c d e
134
• include.lowest et right influent sur la manière dont
les valeurs situées à la frontière des classes seront inclues
ou exclues ;
• dig.lab indique le nombre de chiffres après la virgule à
conserver dans les noms de modalités.
hdv2003 <-
hdv2003 |>
mutate(groupe_ages = cut(age, 5))
hdv2003$groupe_ages |> questionr::freq()
n % val%
(17.9,33.8] 454 22.7 22.7
(33.8,49.6] 628 31.4 31.4
(49.6,65.4] 556 27.8 27.8
(65.4,81.2] 319 16.0 16.0
(81.2,97.1] 43 2.1 2.1
hdv2003 <-
hdv2003 |>
mutate(groupe_ages = cut(age, c(18, 20, 40, 60, 80, 97)))
hdv2003$groupe_ages |> questionr::freq()
n % val%
(18,20] 55 2.8 2.8
(20,40] 660 33.0 33.3
(40,60] 780 39.0 39.3
(60,80] 436 21.8 22.0
(80,97] 52 2.6 2.6
135
NA 17 0.9 NA
Les symboles dans les noms attribués aux classes ont leur im-
portance : ( signifie que la frontière de la classe est exclue,
tandis que [ signifie qu’elle est incluse. Ainsi, (20,40] signifie
« strictement supérieur à 20 et inférieur ou égal à 40 ».
On remarque que du coup, dans notre exemple précédent, la va-
leur minimale, 18, est exclue de notre première classe, et qu’une
observation est donc absente de ce découpage. Pour résoudre
ce problème on peut soit faire commencer la première classe à
17, soit utiliser l’option include.lowest=TRUE :
hdv2003 <-
hdv2003 |>
mutate(groupe_ages = cut(
age,
c(18, 20, 40, 60, 80, 97),
include.lowest = TRUE
))
hdv2003$groupe_ages |> questionr::freq()
n % val%
[18,20] 72 3.6 3.6
(20,40] 660 33.0 33.0
(40,60] 780 39.0 39.0
(60,80] 436 21.8 21.8
(80,97] 52 2.6 2.6
hdv2003 <-
hdv2003 |>
mutate(groupe_ages = cut(
age,
c(18, 20, 40, 60, 80, 97),
include.lowest = TRUE,
right = FALSE
))
136
hdv2003$groupe_ages |> questionr::freq()
n % val%
[18,20) 48 2.4 2.4
[20,40) 643 32.1 32.1
[40,60) 793 39.6 39.6
[60,80) 454 22.7 22.7
[80,97] 62 3.1 3.1
Ď Interface graphique
137
Une démonstration en vidéo de cet add-in est disponible
dans le webin-R #05 (recoder des variables) sur [You-
Tube](https://youtu.be/CokvTbtWdwc?t=2795).
https://youtu.be/CokvTbtWdwc
138
10 Combiner plusieurs
variables
library(tidyverse)
data("hdv2003", package = "questionr")
10.1 if_else()
139
hdv2003 <-
hdv2003 |>
mutate(
statut = if_else(
sexe == "Homme" & age > 60,
"Homme de plus de 60 ans",
"Autre"
)
)
hdv2003 |>
pull(statut) |>
questionr::freq()
n % val%
Autre 1778 88.9 88.9
Homme de plus de 60 ans 222 11.1 11.1
df <- tibble(
sexe = c("f", "f", "h", "h"),
pref_f = c("a", "b", NA, NA),
pref_h = c(NA, NA, "c", "d"),
mesure = c(1.2, 4.1, 3.8, 2.7)
)
df
# A tibble: 4 x 4
sexe pref_f pref_h mesure
140
<chr> <chr> <chr> <dbl>
1 f a <NA> 1.2
2 f b <NA> 4.1
3 h <NA> c 3.8
4 h <NA> d 2.7
df <-
df |>
mutate(
pref = if_else(sexe == "f", pref_f, pref_h),
indicateur = if_else(sexe == "h", mesure - 0.4, mesure - 0.6)
)
df
# A tibble: 4 x 6
sexe pref_f pref_h mesure pref indicateur
<chr> <chr> <chr> <dbl> <chr> <dbl>
1 f a <NA> 1.2 a 0.6
2 f b <NA> 4.1 b 3.5
3 h <NA> c 3.8 c 3.4
4 h <NA> d 2.7 d 2.3
ĺ if_else() et ifelse()
141
10.2 case_when()
hdv2003 <-
hdv2003 |>
mutate(
statut = case_when(
age >= 60 & sexe == "Homme" ~ "Homme, 60 et plus",
age >= 60 & sexe == "Femme" ~ "Femme, 60 et plus",
TRUE ~ "Autre"
)
)
hdv2003 |>
pull(statut) |>
questionr::freq()
n % val%
Autre 1484 74.2 74.2
Femme, 60 et plus 278 13.9 13.9
Homme, 60 et plus 238 11.9 11.9
142
ĺ Important
hdv2003 <-
hdv2003 |>
mutate(
statut = case_when(
sexe == "Homme" ~ "Homme",
age >= 60 & sexe == "Homme" ~ "Homme, 60 et plus",
TRUE ~ "Autre"
)
)
hdv2003 |>
pull(statut) |>
questionr::freq()
n % val%
Autre 1101 55 55
Homme 899 45 45
143
hdv2003 <-
hdv2003 |>
mutate(
statut = case_when(
age >= 60 & sexe == "Homme" ~ "Homme, 60 et plus",
sexe == "Homme" ~ "Homme",
TRUE ~ "Autre"
)
)
hdv2003 |>
pull(statut) |>
questionr::freq()
n % val%
Autre 1101 55.0 55.0
Homme 661 33.1 33.1
Homme, 60 et plus 238 11.9 11.9
10.3 recode_if()
df <- tibble(
pref = factor(c("bleu", "rouge", "autre", "rouge", "autre")),
autre_details = c(NA, NA, "bleu ciel", NA, "jaune")
)
df
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 bleu <NA>
144
2 rouge <NA>
3 autre bleu ciel
4 rouge <NA>
5 autre jaune
df |>
mutate(pref = if_else(autre_details == "bleu ciel", "bleu", pref))
# A tibble: 5 x 2
pref autre_details
<chr> <chr>
1 <NA> <NA>
2 <NA> <NA>
3 bleu bleu ciel
4 <NA> <NA>
5 autre jaune
df |>
mutate(pref = if_else(autre_details == "bleu ciel", factor("bleu"), pref))
145
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 <NA> <NA>
2 <NA> <NA>
3 bleu bleu ciel
4 <NA> <NA>
5 autre jaune
df |>
mutate(pref = if_else(
autre_details != "bleu ciel",
pref,
factor("bleu")
))
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 <NA> <NA>
2 <NA> <NA>
3 bleu bleu ciel
4 <NA> <NA>
5 autre jaune
146
Dès lors, il nous faut soit définir l’argument missing de
dplyr::if_else(), soit être plus précis dans notre test.
df |>
mutate(pref = if_else(
autre_details != "bleu ciel",
pref,
factor("bleu"),
missing = pref
))
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 bleu <NA>
2 rouge <NA>
3 bleu bleu ciel
4 rouge <NA>
5 autre jaune
df |>
mutate(pref = if_else(
autre_details != "bleu ciel" | is.na(autre_details),
pref,
factor("bleu")
))
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 bleu <NA>
2 rouge <NA>
3 bleu bleu ciel
4 rouge <NA>
5 autre jaune
147
en base R fonctionne très bien, mais ne peut pas être intégrée
à un enchaînement d’opérations utilisant le pipe.
Dans ce genre de situation, on pourra être intéressé par la
fonction labelled::recode_if() disponible dans le package
{labelled}. Elle permet de ne modifier que certaines observa-
tions d’un vecteur en fonction d’une condition. Si la condition
vaut FALSE ou NA, les observations concernées restent inchan-
gées. Voyons comment cela s’écrit :
df <-
df |>
mutate(
pref = pref |>
labelled::recode_if(autre_details == "bleu ciel", "bleu")
)
df
# A tibble: 5 x 2
pref autre_details
<fct> <chr>
1 bleu <NA>
2 rouge <NA>
3 bleu bleu ciel
4 rouge <NA>
5 autre jaune
148
11 Étiquettes de variables
11.1 Principe
149
Figure 11.1: Présentation du tableau gtsummary::trial dans
la visionneuse de RStudio
library(labelled)
gtsummary::trial |>
look_for()
gtsummary::trial |>
look_for("months")
150
pos variable label col_type missing values
8 ttdeath Months to Death/Censor dbl 0
Ď Astuce
gtsummary::trial |>
look_for() |>
dplyr::as_tibble()
# A tibble: 8 x 7
pos variable label col_type missing levels value_labels
<int> <chr> <chr> <chr> <int> <named li> <named list>
1 1 trt Chemotherapy Treatment chr 0 <NULL> <NULL>
2 2 age Age dbl 11 <NULL> <NULL>
3 3 marker Marker Level (ng/mL) dbl 10 <NULL> <NULL>
4 4 stage T Stage fct 0 <chr [4]> <NULL>
5 5 grade Grade fct 0 <chr [3]> <NULL>
6 6 response Tumor Response int 7 <NULL> <NULL>
7 7 death Patient Died int 0 <NULL> <NULL>
8 8 ttdeath Months to Death/Censor dbl 0 <NULL> <NULL>
151
de variable à n’importe quel type de variable, qu’elle soit nu-
mérique, textuelle, un facteur ou encore des dates.
v <- c(1, 5, 2, 4, 1)
v |> var_label()
NULL
str(v)
num [1:5] 1 5 2 4 1
- attr(*, "label")= chr "Mon étiquette"
str(v)
num [1:5] 1 5 2 4 1
- attr(*, "label")= chr "Une autre étiquette"
152
num [1:5] 1 5 2 4 1
iris <-
iris |>
set_variable_labels(
Species = NULL,
Sepal.Length = "Longeur du sépale"
)
iris |>
look_for()
153
3 Petal.Length Longueur du pétale dbl 0
4 Petal.Width Largeur du pétale dbl 0
5 Species — fct 0 setosa
versicolor
virginica
iris |>
look_for()
iris |>
subset(Species == "setosa") |>
look_for()
154
On pourra, dans ce cas précis, préférer la fonction
dplyr::filter() qui préserve les attributs et donc les
étiquettes de variables.
iris |>
dplyr::filter(Species == "setosa") |>
look_for()
iris |>
subset(Species == "setosa") |>
copy_labels_from(iris) |>
look_for()
155
12 Étiquettes de valeurs
156
ĺ Important
library(labelled)
v <- c(1, 2, 1, 9)
v
[1] 1 2 1 9
class(v)
[1] "numeric"
157
val_labels(v)
NULL
non oui
1 2
<labelled<double>[4]>
[1] 1 2 1 9
Labels:
value label
1 non
2 oui
class(v)
158
val_label(v, 1)
[1] "non"
val_label(v, 9)
NULL
<labelled<double>[4]>
[1] 1 2 1 9
Labels:
value label
1 non
9 (manquant)
[1] 1 2 1 9
class(v)
[1] "numeric"
159
¾ Mise en garde
v <- c(1, 2, 1, 2)
val_labels(v) <- c(non = 1, oui = 2)
mean(v)
[1] 1.5
[1] NA
df <- dplyr::tibble(
x = c(1, 2, 1, 2),
y = c(3, 9, 9, 3)
)
val_labels(df$x) <- c(non = 1, oui = 2)
val_label(df$y, 9) <- "(manquant)"
df
# A tibble: 4 x 2
x y
<dbl+lbl> <dbl+lbl>
1 1 [non] 3
160
2 2 [oui] 9 [(manquant)]
3 1 [non] 9 [(manquant)]
4 2 [oui] 3
df |>
look_for()
df |>
look_for()
161
df <- df |>
set_value_labels(
x = c(yes = 2),
y = c("a répondu" = 3, "refus de répondre" = 9)
)
df |>
look_for()
df <- df |>
add_value_labels(
x = c(no = 1)
) |>
remove_value_labels(
y = 9
)
df |>
look_for()
12.4 Conversion
162
Mais il faut noter que ces étiquettes de valeur n’indique pas
pour autant de manière systématique le type de variable (ca-
tégorielle ou continue). Les vecteurs labellisés n’ont donc pas
vocation à être utilisés pour l’analyse, notamment le calcul de
modèles statistiques. Ils doivent être convertis en facteurs (pour
les variables catégorielles) ou en vecteurs numériques (pour les
variables continues).
La question qui peut se poser est donc de choisir à quel moment
cette conversion doit avoir lieu dans un processus d’analyse. On
peut considérer deux approches principales.
163
l’approche A, il faudra prévoir une conversion des variables
labellisées au moment de l’analyse.
Á Avertissement
<labelled<double>[7]>
[1] 1 2 9 3 3 2 NA
Labels:
value label
1 oui
2 peut-être
3 non
9 ne sait pas
to_factor(v)
164
Il possible d’indiquer si l’on souhaite, comme étiquettes du fac-
teur, utiliser les étiquettes de valeur (par défaut), les valeurs
elles-mêmes, ou bien les étiquettes de valeurs préfixées par la
valeur d’origine indiquée entre crochets.
to_factor(v, 'l')
to_factor(v, 'v')
[1] 1 2 9 3 3 2 <NA>
Levels: 1 2 3 9
to_factor(v, 'p')
[1] [1] oui [2] peut-être [9] ne sait pas [3] non
[5] [3] non [2] peut-être <NA>
Levels: [1] oui [2] peut-être [3] non [9] ne sait pas
165
12.4.3 Convertir un vecteur labellisé en numérique ou
en texte
unclass(x)
[1] 1 2 9 3 3 2 NA
attr(,"labels")
oui peut-être non ne sait pas
1 2 3 9
unclass(y)
166
Une alternative est d’utiliser labelled::remove_labels() qui
supprimera toutes les étiquettes, y compris les étiquettes de va-
riable. Pour conserver les étiquettes de variables et ne suppri-
mer que les étiquettes de valeurs, on indiquera keep_var_label
= TRUE.
[1] 1 2 9 3 3 2 NA
[1] 1 2 9 3 3 2 NA
attr(,"label")
[1] "Etiquette de variable"
remove_labels(y)
to_character(x)
167
12.4.4 Conversion conditionnelle en facteurs
df <- dplyr::tibble(
a = c(1, 1, 2, 3),
b = c(1, 1, 2, 3),
c = c(1, 1, 2, 2),
d = c("a", "a", "b", "c"),
e = c(1, 9, 1, 2),
f = 1:4,
g = as.Date(c(
"2020-01-01", "2020-02-01",
"2020-03-01", "2020-04-01"
))
) |>
set_value_labels(
a = c(No = 1, Yes = 2),
168
b = c(No = 1, Yes = 2, DK = 3),
c = c(No = 1, Yes = 2, DK = 3),
d = c(No = "a", Yes = "b"),
e = c(No = 1, Yes = 2)
)
df |> look_for()
169
5 e — fct 0 No
Yes
9
6 f — int 0
7 g — date 0
170
unlabelled(df, levels = "prefixed") |>
look_for()
171
13 Valeurs manquantes
172
uniquement sur les réponses valides, en fonction du besoin de
l’analyse et de ce que l’on cherche à montrer.
Afin d’éviter toute perte d’informations lors d’un import de
données depuis Stata, SAS et SPSS, le package {haven} pro-
pose une implémentation sous R des tagged NAs et des user
NAs. Le package {labelled} fournit quant à lui différentes
fonctions pour les manipuler aisément.
library(labelled)
[1] 1 2 3 NA NA NA
is.na(x)
173
Pour afficher les étiquettes associées à ces valeurs man-
quantes, il faut avoir recours à labelled::na_tag(),
labelled::print_tagged_na() ou encore labelled::format_tagged_na().
na_tag(x)
print_tagged_na(x)
format_tagged_na(x)
[1] " 1" " 2" " 3" "NA(a)" "NA(z)" " NA"
is.na(x)
is_regular_na(x)
is_tagged_na(x)
174
is_tagged_na(x, "a")
Ĺ Note
is_tagged_na(y)
format_tagged_na(y)
[1] "double"
format_tagged_na(z)
175
13.1.2 Valeurs uniques, doublons et tris
x |>
unique() |>
print_tagged_na()
[1] 1 2 NA(a)
x |>
unique_tagged_na() |>
print_tagged_na()
x |>
duplicated()
176
x |>
duplicated_tagged_na()
x |>
sort(na.last = TRUE) |>
print_tagged_na()
x |>
sort_tagged_na() |>
print_tagged_na()
x <- c(
1, 0,
1, tagged_na("r"),
0, tagged_na("d"),
tagged_na("z"), NA
)
val_labels(x) <- c(
no = 0,
yes = 1,
"don't know" = tagged_na("d"),
refusal = tagged_na("r")
)
x
177
<labelled<double>[8]>
[1] 1 0 1 NA(r) 0 NA(d) NA(z) NA
Labels:
value label
0 no
1 yes
NA(d) don't know
NA(r) refusal
x |> to_factor()
x |>
to_factor(explicit_tagged_na = TRUE)
x |>
to_factor(
levels = "prefixed",
explicit_tagged_na = TRUE
)
178
[1] [1] yes [0] no [1] yes [NA(r)] refusal
[5] [0] no [NA(d)] don't know [NA(z)] NA(z) <NA>
Levels: [0] no [1] yes [NA(d)] don't know [NA(r)] refusal [NA(z)] NA(z)
x |>
tagged_na_to_user_na()
<labelled_spss<double>[8]>
[1] 1 0 1 3 0 2 4 NA
Missing range: [2, 4]
Labels:
value label
0 no
1 yes
2 don't know
3 refusal
4 NA(z)
x |>
tagged_na_to_user_na(user_na_start = 10)
<labelled_spss<double>[8]>
[1] 1 0 1 11 0 10 12 NA
Missing range: [10, 12]
Labels:
value label
0 no
1 yes
10 don't know
11 refusal
12 NA(z)
179
La fonction labelled::tagged_na_to_regular_na() conver-
tit les tagged NAs en valeurs manquantes classiques (regular
NAs).
x |>
tagged_na_to_regular_na()
<labelled<double>[8]>
[1] 1 0 1 NA 0 NA NA NA
Labels:
value label
0 no
1 yes
x |>
tagged_na_to_regular_na() |>
is_tagged_na()
ĺ Important
180
Il convient de garder en mémoire que la très grande ma-
jorité des fonctions de R ne prendront pas en compte ces
métadonnées et traiteront donc ces valeurs comme des va-
leurs valides. C’est donc à l’utilisateur de convertir, au
besoin, ces les valeurs indiquées comme manquantes en
réelles valeurs manquantes (NA).
13.2.1 Création
<labelled_spss<double>[8]>
[1] 1 2 3 9 1 3 2 NA
Missing values: 9
Labels:
value label
1 faible
3 fort
9 ne sait pas
181
na_values(v) <- NULL
v
<labelled<double>[8]>
[1] 1 2 3 9 1 3 2 NA
Labels:
value label
1 faible
3 fort
9 ne sait pas
<labelled_spss<double>[8]>
[1] 1 2 3 9 1 3 2 NA
Missing range: [5, Inf]
Labels:
value label
1 faible
3 fort
9 ne sait pas
On peut noter que les user NAs peuvent cohabiter avec des
regular NAs ainsi qu’avec des étiquettes de valeurs (value labels,
cf. Chapitre 12).
Pour manipuler les variables d’un tableau de données, on peut
également avoir recours à labelled::set_na_values() et
labelled::set_na_range().
df <-
dplyr::tibble(
s1 = c("M", "M", "F", "F"),
s2 = c(1, 1, 2, 9)
) |>
182
set_na_values(s2 = 9)
df$s2
<labelled_spss<double>[4]>
[1] 1 1 2 9
Missing values: 9
df <-
df |>
set_na_values(s2 = NULL)
df$s2
<labelled<double>[4]>
[1] 1 1 2 9
13.2.2 Tests
<labelled_spss<double>[8]>
[1] 1 2 3 9 1 3 2 NA
Missing range: [5, Inf]
Labels:
value label
1 faible
3 fort
9 ne sait pas
v |> is.na()
183
v |> is_user_na()
v |> is_regular_na()
13.2.3 Conversion
<labelled_spss<integer>[10]>
[1] 1 2 3 4 5 11 12 13 14 15
Missing range: [10, Inf]
mean(x)
[1] 8
x |>
user_na_to_na()
<labelled<integer>[10]>
[1] 1 2 3 4 5 NA NA NA NA NA
184
x |>
user_na_to_na() |>
mean(na.rm = TRUE)
[1] 3
x |>
user_na_to_tagged_na() |>
print_tagged_na()
x |>
user_na_to_tagged_na() |>
mean(na.rm = TRUE)
[1] 3
x |>
remove_user_na()
<labelled<integer>[10]>
[1] 1 2 3 4 5 11 12 13 14 15
185
x |>
remove_user_na() |>
mean()
[1] 8
x <- c(1, 2, 9, 2)
val_labels(x) <- c(oui = 1, non = 2, refus = 9)
na_values(x) <- 9
x |>
to_factor(user_na_to_na = TRUE)
x |>
to_factor(user_na_to_na = FALSE)
186
14 Import & Export de
données
187
• Pour les variables textuelles, y a-t-il des valeurs man-
quantes et si oui comment sont-elles indiquées ? Par
exemple, le texte NA est parfois utilisé.
188
Vous pourrez remarquer que RStudio fait appel à l’extension
{readr} du tidyverse pour l’import des données via la fonction
readr::read_csv().
{readr} essaie de deviner le type de chacune des colonnes, en
se basant sur les premières observations. En cliquant sur le nom
d’une colonne, il est possible de modifier le type de la variable
importée. Il est également possible d’exclure une colonne de
l’import (skip).
library(readr)
d <- read_delim(
"http://larmarange.github.io/analyse-R/data/exemple_texte_tabule.txt",
delim = "\t",
quote = "'"
)
189
Dans des manuels ou des exemples en ligne, vous trou-
verez parfois mention des fonctions utils::read.table(),
utils::read.csv(), utils::read.csv2(), utils::read.delim()
ou encore utils::read.delim2(). Il s’agit des fonctions na-
tives et historiques de R (extension {utils}) dédiées à
l’import de fichiers textes. Elles sont similaires à celles de
{readr} dans l’idée générale mais diffèrent dans leurs détails
et les traitements effectués sur les données (pas de détection
des dates par exemple). Pour plus d’information, vous pouvez
vous référer à la page d’aide de ces fonctions.
library(readxl)
donnees <- read_excel("data/fichier.xlsx")
190
on pourra indiquer le type souhaité de chaque colonne avec
col_types.
RStudio propose également pour les fichiers Excel un assis-
tant d’importation, similaire à celui pour les fichiers texte, per-
mettant de faciliter l’import.
14.3.1 SPSS
Les fichiers générés par SPSS sont de deux types : les fichiers
SPSS natifs (extension .sav) et les fichiers au format SPSS
export (extension .por).
Dans les deux cas, on aura recours à la fonction haven::read_spss() :
library(haven)
donnees <- read_spss("data/fichier.sav", user_na = TRUE)
191
Ď Valeurs manquantes
14.3.2 SAS
library(haven)
donnees <- read_sas("data/fichier.sas7bdat")
library(haven)
donnees <- read_sas(
"data/fichier.sas7bdat",
catalog_file = "data/fichier.sas7bcat"
)
Ĺ Note
192
library(foreign)
donnees <- read.xport("data/fichier.xpt")
14.3.3 Stata
library(haven)
donnees <- read_dta("data/fichier.dta")
ĺ Important
14.3.4 dBase
library(foreign)
donnees <- read.dbf("data/fichier.dbf")
193
un même fichier. L’usage est d’utiliser l’extension .RData pour
les fichiers de données R. La fonction à utiliser s’appelle tout
simplement save().
Par exemple, si l’on souhaite sauvegarder son tableau de don-
nées d ainsi que les objets tailles et poids dans un fichier
export.RData :
load("export.RData")
¾ Mise en garde
save.image()
194
donnees <- readRDS("mes_donnees.rds")
195
15 Mettre en forme des
nombres
library(scales)
x <- c(0.0023, .123, 4.567, 874.44, 8957845)
number(x)
f <- label_number()
f(x)
label_number()(x)
196
[1] "0.00" "0.12" "4.57" "874.44" "8 957 845.00"
15.1 label_number()
label_number(accuracy = NULL)(x)
label_number(accuracy = .1)(x)
label_number(accuracy = .25)(x)
197
label_number(accuracy = 10)(x)
198
label_number(accuracy = 10^-9, small.mark = "|", small.interval = 3)(x)
label_number(style_negative = "parens")(y)
[1] "4.5 µg" "12.4 mg" "2.3 g" "47.6 kg" "789.5 Mg"
15.2.1 label_comma()
199
label_comma()(x)
15.2.2 label_percent()
label_percent()(x)
15.2.3 label_dollar()
label_dollar()(x)
label_dollar(prefix = "", suffix = " €", accuracy = .01, big.mark = " ")(x)
200
[1] "0.00 €" "0.12 €" "4.57 €" "874.44 €"
[5] "8 957 845.00 €"
15.2.4 label_pvalue()
15.2.5 label_scientific()
201
15.2.6 label_bytes()
label_bytes(units = "auto_binary")(b)
15.2.7 label_ordinal()
label_ordinal()(1:5)
label_ordinal(rules = ordinal_french())(1:5)
202
15.2.8 label_date(), label_date_short() &
label_time()
scales::label_date(), scales::label_date_short() et
scales::label_time() peuvent être utilisées pour la mise en
forme de dates.
label_date()(as.Date("2020-02-14"))
[1] "2020-02-14"
label_date(format = "%d/%m/%Y")(as.Date("2020-02-14"))
[1] "14/02/2020"
label_date_short()(as.Date("2020-02-14"))
[1] "14\nfévr.\n2020"
15.2.9 label_wrap()
x <- "Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs lignes. C
label_wrap(80)(x)
[1] "Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs\nlignes. Cepe
203
label_wrap(80)(x) |> message()
Ceci est un texte assez long et que l'on souhaiterait afficher sur plusieurs
lignes. Cependant, on souhaite éviter que des coupures apparaissent au milieu
d'un mot.
15.3.1 style_number()
library(gtsummary)
x <- c(0.123, 0.9, 1.1234, 12.345, -0.123, -0.9, -1.1234, -132.345)
style_number(x, digits = 1)
204
[1] "0.1" "0.9" "1.1" "12.3" "-0.1" "-0.9" "-1.1" "-132.3"
Ď Astuce
¾ Mise en garde
15.3.2 style_sigfig()
205
style_sigfig(x)
style_sigfig(x, digits = 3)
15.3.3 style_percent()
style_percent(v)
style_percent(v, digits = 1)
206
15.3.4 style_pvalue()
style_pvalue(p)
15.3.5 style_ratio()
r <- c(0.123, 0.9, 1.1234, 12.345, 101.234, -0.123, -0.9, -1.1234, -12.345, -101.234)
style_ratio(r)
[1] "0.12" "0.90" "1.12" "12.3" "101" "-0.12" "-0.90" "-1.12" "-12.3"
[10] "-101"
207
15.4 Bonus : signif_stars() de {ggstats}
15.5
208
16 Couleurs & Palettes
library(tidyverse)
ggplot(iris) +
aes(x = Petal.Length) +
geom_histogram(colour = "red", fill = "blue")
209
20
count
10
0
2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length) +
geom_histogram(colour = "#666666", fill = "#FF0000")
210
20
count
10
0
2 4 6
Petal.Length
[1] "#FF0000"
211
YlOrRd
YlOrBr
YlGnBu
YlGn
Reds
RdPu
Purples
PuRd
PuBuGn
PuBu
OrRd
Oranges
Greys
Greens
GnBu
BuPu
BuGn
Blues
Set3
Set2
Set1
Pastel2
Pastel1
Paired
Dark2
Accent
Spectral
RdYlGn
RdYlBu
RdGy
RdBu
PuOr
PRGn
PiYG
BrBG
¾ Mise en garde
212
16.3.2 Palettes de Paul Tol
library(khroma)
plot_scheme(colour("bright")(7), colours = TRUE)
ggplot(mpg) +
aes(x = displ, y = hwy, colour = class) +
geom_point() +
khroma::scale_colour_bright()
213
40
class
2seater
compact
30 midsize
hwy
minivan
pickup
subcompact
20
suv
2 3 4 5 6 7
displ
214
#762A83 #C2A5CF #F7F7F7 #ACD39E #1B7837
#9970AB #E7D4E8 #D9F0D3 #5AAE61 #FFEE99
gt::info_paletteer()
215
paletteer::scale_color_paletteer_d() et paletteer::scale_fill_paletteer_d()
permettront d’utiliser une palette donnée avec {ggplot2}.
library(paletteer)
paletteer_d("khroma::bright", n = 5)
<colors>
#4477AAFF #EE6677FF #228833FF #CCBB44FF #66CCEEFF
ggplot(mpg) +
aes(x = displ, y = hwy, colour = class) +
geom_point() +
scale_color_paletteer_d("khroma::bright")
40
class
2seater
compact
30 midsize
hwy
minivan
pickup
subcompact
20
suv
2 3 4 5 6 7
displ
paletteer_c("viridis::viridis", n = 6)
<colors>
#440154FF #414487FF #2A788EFF #22A884FF #7AD151FF #FDE725FF
216
ggplot(iris) +
aes(x = Sepal.Length, y = Sepal.Width, colour = Petal.Length) +
geom_point() +
scale_colour_paletteer_c("viridis::viridis", direction = -1)
4.5
4.0
Petal.Length
Sepal.Width
3.5 6
5
4
3.0
3
2
1
2.5
2.0
5 6 7 8
Sepal.Length
217
partie III
Analyses
218
17 Graphiques avec ggplot2
17.1 Ressources
219
tidy, c’est-à-dire avec une ligne par observation et les différentes
valeurs à représenter sous forme de variables du tableau.
220
des points, ggplot2::geom_line() pour des lignes,
ggplot2::geom_bar() pour des barres ou encore ggplot2::geom_area()
pour des aires. Il existe de nombreuses géométries différentes21 , 21
On trouvera une liste dans la cheat
chacune prenant en compte certaines esthétiques, certaines sheet de {ggplot2}, voir Section 17.3.
étant requises pour cette géométrie et d’autres optionnelles.
La liste des esthétiques prises en compte par chaque géométrie
est indiquée dans l’aide en ligne de cette dernière.
Voici un exemple minimal de graphique avec {ggplot2} :
library(ggplot2)
p <-
ggplot(iris) +
aes(
x = Petal.Length,
y = Petal.Width,
colour = Species
) +
geom_point()
p
2.5
2.0
Species
Petal.Width
1.5
setosa
versicolor
1.0 virginica
0.5
0.0
2 4 6
Petal.Length
221
ĺ Syntaxe additive
p +
labs(
x = "Longueur du pétale",
y = "Largeur du pétale",
colour = "Espèce"
) +
ggtitle(
"Relation entre longueur et largeur des pétales",
subtitle = "Jeu de données Iris"
) +
scale_x_continuous(breaks = 1:7) +
scale_y_continuous(
222
labels = scales::label_number(decimal.mark = ",")
) +
coord_equal() +
facet_grid(cols = vars(Species)) +
guides(
color = guide_legend(nrow = 2)
) +
theme_light() +
theme(
legend.position = "bottom",
axis.title = element_text(face = "bold")
)
setosa virginica
Espèce
versicolor
223
Figure 17.4: Cheatsheet ggplot2
17.3 Cheatsheet
224
Figure 17.6: Import de données au lancement d’esquisse
225
modifier les échelles de couleurs et l’apparence du graphique,
et de filtrer les observations inclues dans le graphique.
Le menu Code permet de récupérer le code correspondant au
graphique afin de pouvoir le copier/coller dans un script.
17.5 webin-R
226
17.6 Combiner plusieurs graphiques
p1 <- ggplot(mtcars) +
aes(x = wt, y = mpg) +
geom_point()
p2 <- ggplot(mtcars) +
aes(x = factor(cyl)) +
geom_bar()
p3 <- ggplot(mtcars) +
aes(x = factor(cyl), y = mpg) +
geom_violin() +
theme(axis.title = element_text(size = 20))
p4 <- ggplot(mtcars) +
aes(x = factor(cyl), y = mpg) +
geom_boxplot() +
ylab(NULL)
library(patchwork)
p1 + p2 + p3 + p4
227
35
30
10
count
25
mpg
20 5
15
10 0
2 3 4 5 4 6 8
wt factor(cyl)
35 35
30 30
mpg
25 25
20 20
15 15
10 10
4 6 8 4 6 8
factor(cyl) factor(cyl)
p1 | p2 | p3
35 35
30 30
10
25 25
mpg
count
mpg
20 20
5
15 15
10 0 10
2 3 4 5 4 6 8 4 6 8
wt factor(cyl) factor(cyl)
p1 / p2
228
35
30
25
mpg
20
15
10
2 3 4 5
wt
10
count
0
4 6 8
factor(cyl)
(p1 + p2) / p3
35
30
10
count
25
mpg
20 5
15
10 0
2 3 4 5 4 6 8
wt factor(cyl)
35
30
mpg
25
20
15
10
4 6 8
factor(cyl)
(p1 + p2) | p3
229
35 35
30 30
10
25 25
mpg
count
mpg
20 20
5
15 15
10 0 10
2 3 4 5 4 6 8 4 6 8
wt factor(cyl) factor(cyl)
35
30
10
count
25
mpg
20 5
15
10 0
2 3 4 5 4 6 8
wt factor(cyl)
35 35
30 30
mpg
25 25
20 20
15 15
10 10
4 6 8 4 6 8
factor(cyl) factor(cyl)
230
p1 + p2 + p3 + p4 + plot_layout(widths = c(2, 1))
35
30
10
count
25
mpg
20 5
15
10 0
2 3 4 5 4 6 8
wt factor(cyl)
35 35
30 30
mpg
25 25
20 20
15 15
10 10
4 6 8 4 6 8
factor(cyl) factor(cyl)
p1 + p2 + p3 + p4 +
plot_annotation(
title = "Titre du graphique",
subtitle = "sous-titre",
caption = "notes additionelles",
tag_levels = "a",
tag_suffix = "."
)
231
Titre du graphique
sous−titre
a. 35
b.
30
count
10
mpg
25
20 5
15
10 0
2 3 4 5 4 6 8
wt factor(cyl)
c. 35
d. 35
mpg
30 30
25 25
20 20
15 15
10 10
4 6 8 4 6 8
factor(cyl) factor(cyl)
notes additionelles
232
18 Statistique univariée &
Intervalles de confiance
library(ggplot2)
ggplot(iris) +
aes(x = Petal.Length) +
geom_histogram()
233
`stat_bin()` using `bins = 30`. Pick better value with `binwidth`.
20
count
10
0
2 4 6
Petal.Length
Ď Astuce
234
On peut personnaliser la couleur de remplissage des rectangles
en indiquant une valeur fixe pour l’esthétique fill dans
l’appel de ggplot2::geom_histogram() (et non via la fonc-
tion ggplot2::aes() puisqu’il ne s’agit pas d’une variable du
tableau de données). L’esthétique colour permet de spécifier la
couleur du trait des rectangles. Enfin, le paramètre binwidth
permet de spécifier la largeur des barres.
ggplot(iris) +
aes(x = Petal.Length) +
geom_histogram(
fill ="lightblue",
colour = "black",
binwidth = 1
) +
xlab("Longeur du pétale") +
ylab("Effectifs")
30
Effectifs
20
10
0
2 4 6
Longeur du pétale
235
ggplot(iris) +
aes(x = Petal.Length) +
geom_histogram(bins = 10, colour = "black")
40
30
count
20
10
0
2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length) +
geom_density(adjust = .5)
236
0.4
0.3
density
0.2
0.1
0.0
2 4 6
Petal.Length
237
1000
750
count
500
250
0
Exerce une profession
ChomeurEtudiant, eleve RetraiteRetire des affairesAu foyer Autre inactif
occup
Ď Astuce
library(ggstats)
ggplot(hdv2003) +
238
aes(x = occup, y = after_stat(prop), by = 1) +
geom_bar(stat = "prop") +
scale_y_continuous(labels = scales::label_percent())
50%
40%
30%
prop
20%
10%
0%
Exerce une profession
ChomeurEtudiant, eleve RetraiteRetire des affairesAu foyer Autre inactif
occup
ggplot(hdv2003) +
aes(x = forcats::fct_infreq(occup),
y = after_stat(prop), by = 1) +
geom_bar(stat = "prop",
fill = "#4477AA", colour = "black") +
geom_text(
aes(label = after_stat(prop) |>
scales::percent(accuracy = .1)),
stat = "prop",
nudge_y = .02
) +
theme_minimal() +
239
theme(
panel.grid = element_blank(),
axis.text.y = element_blank()
) +
xlab(NULL) + ylab(NULL) +
ggtitle("Occupation des personnes enquêtées")
19.6%
8.6%
6.7%
4.7% 4.2% 3.8%
240
n’indique rien, toutes les variables du tableau de données
sont considérées). Il faut noter que l’argument include de
gtsummary::tbl_summary() utilise la même syntaxe dite
tidy select que dplyr::select() (cf. Section 8.2.1). On
peut indiquer tout autant des variables catégorielles que des
variables continues.
library(gtsummary)
#Uighur
hdv2003 |>
tbl_summary(include = c(age, occup))
Characteristic N = 2,000
age 48 (35, 60)
occup
Exerce une profession 1,049 (52%)
Chomeur 134 (6.7%)
Etudiant, eleve 94 (4.7%)
Retraite 392 (20%)
Retire des affaires 77 (3.9%)
Au foyer 171 (8.6%)
Autre inactif 83 (4.2%)
241
Par défaut, {gtsummary} considère qu’une variable est ca-
tégorielle s’il s’agit d’un facteur, d’une variable textuelle
ou d’une variable numérique ayant moins de 10 valeurs
différentes.
Une variable sera considérée comme dichotomique (va-
riable catégorielle à seulement deux modalités) s’il s’agit
d’un vecteur logique (TRUE/FALSE), d’une variable tex-
tuelle codée yes/no ou d’une variable numérique codée
0/1.
Dans les autres cas, une variable numérique sera considé-
rée comme continue.
Si vous utilisez des vecteurs labellisés (cf. Cha-
pitre 12), vous devez les convertir, en amont, en
facteurs ou en variables numériques. Voir l’extension
{labelled} et les fonctions labelled::to_factor(),
labelled::unlabelled() et unclass().
Au besoin, il est possible de forcer le type d’une variable
avec l’argument type de gtsummary::tbl_summary().
{gtsummary} fournit des sélecteurs qui peuvent être utili-
sés dans les options des différentes fonctions, en particulier
gtsummary::all_continuous() pour les variables conti-
nues, gtsummary::all_dichotolous() pour les variables
dichotomiques et gtsummary::all_categorical() pour
les variables catégorielles. Cela inclue les variables dicho-
tomiques. Il faut utiliser all_categorical(dichotomous
= FALSE) pour sélectionner les variables catégorielles en
excluant les variables dichotomiques.
242
La fonction gtsummary::theme_gtsummary_language() per-
met de modifier la langue utilisée par défaut dans les tableaux.
Les options decimal.mark et big.mark permettent de définir
respectivement le séparateur de décimales et le séparateur des
milliers. Ainsi, pour présenter un tableau en français, on appli-
quera en début de script :
theme_gtsummary_language(
language = "fr",
decimal.mark = ",",
big.mark = " "
)
hdv2003 |>
tbl_summary(include = c(age, occup))
Caractéristique N = 2 000
age 48 (35 – 60)
occup
Exerce une profession 1 049 (52%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Retraite 392 (20%)
Retire des affaires 77 (3,9%)
Au foyer 171 (8,6%)
Autre inactif 83 (4,2%)
243
18.2.2 Étiquettes des variables
hdv2003 |>
labelled::set_variable_labels(
occup = "Occupation actuelle"
) |>
tbl_summary(
include = c(age, occup, heures.tv),
label = list(age ~ "Âge médian")
)
Caractéristique N = 2 000
Âge médian 48 (35 – 60)
Occupation actuelle
Exerce une profession 1 049 (52%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Retraite 392 (20%)
Retire des affaires 77 (3,9%)
Au foyer 171 (8,6%)
Autre inactif 83 (4,2%)
heures.tv 2,00 (1,00 – 3,00)
Manquant 5
244
Pour modifier les modalités d’une variable catégorielle, il faut
modifier en amont les niveaux du facteur correspondant.
trial |>
tbl_summary(label = age ~ "Âge")
trial |>
tbl_summary(label = list(age ~ "Âge", trt ~ "Traitement"))
trial |>
tbl_summary(label = age ~ "Âge")
trial |>
tbl_summary(label = "age" ~ "Âge")
v <- "age"
trial |>
tbl_summary(label = v ~ "Âge")
245
trial |>
tbl_summary(label = c("age", "trt") ~ "Une même étiquette")
trial |>
tbl_summary(label = c(age, trt) ~ "Une même étiquette")
trial |>
tbl_summary(
label = everything() ~ "Une même étiquette"
)
trial |>
tbl_summary(
label = starts_with("a") ~ "Une même étiquette"
)
trial |>
tbl_summary(
label = c(everything(), -age, -trt) ~ "Une même étiquette"
)
trial |>
tbl_summary(
label = age:trt ~ "Une même étiquette"
)
246
trial |>
tbl_summary(
label = all_continuous() ~ "Une même étiquette"
)
trial |>
tbl_summary(
label = list(
all_continuous() ~ "Variable continue",
all_dichotomous() ~ "Variable dichotomique",
all_categorical(dichotomous = FALSE) ~ "Variable catégorielle"
)
)
trial |>
tbl_summary(label = ~ "Une même étiquette")
trial |>
tbl_summary(
label = everything() ~ "Une même étiquette"
)
247
hdv2003 |>
tbl_summary(
include = c(age, heures.tv),
statistic =
all_continuous() ~ "Moy. : {mean} [min-max : {min} - {max}]"
)
Caractéristique N = 2 000
age Moy. : 48 [min-max : 18 - 97]
heures.tv Moy. : 2,25 [min-max : 0,00 - 12,00]
Manquant 5
hdv2003 |>
tbl_summary(
include = c(age, heures.tv),
statistic = list(
age ~ "Méd. : {median} [{p25} - {p75}]",
heures.tv ~ "Moy. : {mean} ({sd})"
)
)
248
Table 18.5: statistiques personnalisées pour une variable conti-
nue (2)
Caractéristique N = 2 000
age Méd. : 48 [35 - 60]
heures.tv Moy. : 2,25 (1,78)
Manquant 5
Caractéristique N = 2 000
heures.tv MC : 8,20
Manquant 5
249
hdv2003 |>
tbl_summary(
include = occup,
statistic = all_categorical() ~ "{p} % ({n}/{N})"
)
Caractéristique N = 2 000
occup
Exerce une profession 52 % (1 049/2 000)
Chomeur 6,7 % (134/2 000)
Etudiant, eleve 4,7 % (94/2 000)
Retraite 20 % (392/2 000)
Retire des affaires 3,9 % (77/2 000)
Au foyer 8,6 % (171/2 000)
Autre inactif 4,2 % (83/2 000)
hdv2003 |>
tbl_summary(
include = occup,
sort = all_categorical() ~ "frequency"
)
250
Table 18.8: variable catégorielle triée par fréquence
Caractéristique N = 2 000
occup
Exerce une profession 1 049 (52%)
Retraite 392 (20%)
Au foyer 171 (8,6%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Autre inactif 83 (4,2%)
Retire des affaires 77 (3,9%)
251
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Caractéristique N = 2 000
age 48 (17)
heures.tv 2,00 [1,00 - 3,00]
Manquant 5
occup
Exerce une profession 1 049 (52%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Retraite 392 (20%)
Retire des affaires 77 (3,9%)
Au foyer 171 (8,6%)
Autre inactif 83 (4,2%)
tbl |>
add_stat_label()
Caractéristique N = 2 000
age, Moyenne (ET) 48 (17)
heures.tv, Médiane [EI] 2,00 [1,00 - 3,00]
Manquant 5
252
Caractéristique N = 2 000
occup, n (%)
Exerce une profession 1 049 (52%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Retraite 392 (20%)
Retire des affaires 77 (3,9%)
Au foyer 171 (8,6%)
Autre inactif 83 (4,2%)
tbl |>
add_stat_label(location = "column")
253
du tableau de données trial est traitée comme variable conti-
nue, death comme dichotomique (seule la valeur 1 est affichée)
et grade comme variable catégorielle.
trial |>
tbl_summary(
include = c(grade, age, death)
)
Caractéristique N = 200
Grade
I 68 (34%)
II 68 (34%)
III 64 (32%)
Age 47 (38 – 57)
Manquant 11
Patient Died 112 (56%)
trial |>
tbl_summary(
include = c(grade, death),
type = list(
grade ~ "dichotomous",
death ~ "categorical"
),
value = grade ~ "III",
label = grade ~ "Grade III"
254
)
Caractéristique N = 200
Grade III 64 (32%)
Patient Died
0 88 (44%)
1 112 (56%)
Caractéristique N = 200
alea
1 50 (25%)
2 45 (23%)
3 42 (21%)
255
Caractéristique N = 200
4 63 (32%)
trial |>
tbl_summary(
include = alea,
type = alea ~ "continuous"
)
Caractéristique N = 200
alea 3 (2 – 4)
hdv2003 |>
tbl_summary(
include = c(age, heures.tv),
type = age ~ "continuous2",
256
statistic =
all_continuous2() ~ c(
"{median} ({p25} - {p75})",
"{mean} ({sd})",
"{min} - {max}"
)
)
Caractéristique N = 2 000
age
Médiane (EI) 48 (35 - 60)
Moyenne (ET) 48 (17)
Étendue 18 - 97
heures.tv 2,00 (1,00 – 3,00)
Manquant 5
hdv2003 |>
tbl_summary(
include = c(age, occup),
digits = list(
all_continuous() ~ 1,
257
all_categorical() ~ c(0, 1)
)
)
Caractéristique N = 2 000
age 48,0 (35,0 – 60,0)
occup
Exerce une profession 1 049 (52,5%)
Chomeur 134 (6,7%)
Etudiant, eleve 94 (4,7%)
Retraite 392 (19,6%)
Retire des affaires 77 (3,9%)
Au foyer 171 (8,6%)
Autre inactif 83 (4,2%)
258
hdv2003 |>
tbl_summary(
include = age,
digits =
all_continuous() ~ c(style_percent, style_sigfig, style_ratio)
)
Caractéristique N = 2 000
age 4 800 (35 – 60,0)
trial |>
tbl_summary(
include = marker,
statistic = ~ "{mean} pour 100",
digits = ~ function(x){style_percent(x, digits = 1)}
)
259
Table 18.19: passer une fonction personnalisée à digits (syntaxe
1)
Caractéristique N = 200
Marker Level (ng/mL) 91,6 pour 100
Manquant 10
trial |>
tbl_summary(
include = marker,
statistic = ~ "{mean} pour 100",
digits = ~ \(x){style_percent(x, digits = 1)}
)
Caractéristique N = 200
Marker Level (ng/mL) 91,6 pour 100
Manquant 10
trial |>
tbl_summary(
include = marker,
statistic = ~ "{mean} pour 100",
digits = ~ purrr::partial(style_percent, digits = 1)
260
)
Caractéristique N = 200
Marker Level (ng/mL) 91,6 pour 100
Manquant 10
trial |>
tbl_summary(
include = marker,
statistic = ~ "{mean}",
digits = ~ scales::label_number(
accuracy = .01,
suffix = " ng/mL",
decimal.mark = ","
)
)
261
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Caractéristique N = 200
Marker Level (ng/mL) 0,92 ng/mL
Manquant 10
hdv2003 |>
tbl_summary(
include = c(age, heures.tv),
missing = "always",
missing_text = "Nbre observations manquantes"
)
Caractéristique N = 2 000
age 48 (35 – 60)
Nbre observations manquantes 0
heures.tv 2,00 (1,00 – 3,00)
Nbre observations manquantes 5
262
Caractéristique N = 2 000
hdv2003 |>
dplyr::mutate(
trav.imp.explicit = trav.imp |>
forcats::fct_na_value_to_level("(non renseigné)")
) |>
tbl_summary(
include = c(trav.imp, trav.imp.explicit)
)
Caractéristique N = 2 000
trav.imp
Le plus important 29 (2,8%)
Aussi important que le reste 259 (25%)
Moins important que le reste 708 (68%)
Peu important 52 (5,0%)
Manquant 952
trav.imp.explicit
Le plus important 29 (1,5%)
Aussi important que le reste 259 (13%)
Moins important que le reste 708 (35%)
Peu important 52 (2,6%)
(non renseigné) 952 (48%)
263
18.2.9 Ajouter les effectifs observés
hdv2003 |>
tbl_summary(
include = c(heures.tv, trav.imp),
missing = "no"
) |>
add_n()
Caractéristique N N = 2 000
heures.tv 1 995 2,00 (1,00 – 3,00)
trav.imp 1 048
Le plus important 29 (2,8%)
Aussi important que le reste 259 (25%)
Moins important que le reste 708 (68%)
Peu important 52 (5,0%)
264
• range() pour l’étendue
• median() pour la médiane
[1] NA
[1] 2.246566
[1] 1.775853
[1] 0
[1] 12
[1] 0 12
[1] 2
265
hdv2003$heures.tv |> quantile(na.rm = TRUE)
hdv2003$heures.tv |>
quantile(
probs = c(.2, .4, .6, .8),
na.rm = TRUE
)
Les fonctions de base pour le calcul d’un tri à plat sont les
fonctions table() et xtabs(). Leur syntaxe est quelque peu
différente. On passe un vecteur entier à table() alors que la
syntaxe de xtabs() se rapproche de celle d’un modèle linéaire :
on décrit le tableau attendu à l’aide d’une formule et on indique
le tableau de données. Les deux fonctions renvoient le même
résultat.
266
trav.imp
Le plus important Aussi important que le reste
29 259
Moins important que le reste Peu important
708 52
prop.table(tbl)
trav.imp
Le plus important Aussi important que le reste
0.02767176 0.24713740
Moins important que le reste Peu important
0.67557252 0.04961832
hdv2003$trav.imp |>
questionr::freq(total = TRUE)
n % val%
Le plus important 29 1.5 2.8
Aussi important que le reste 259 13.0 24.7
Moins important que le reste 708 35.4 67.6
Peu important 52 2.6 5.0
NA 952 47.6 NA
Total 2000 100.0 100.0
267
18.4 Intervalles de confiance
Á Avertissement
hdv2003 |>
tbl_summary(
include = c(age, heures.tv, trav.imp),
statistic = age ~ "{mean} ({sd})"
) |>
add_ci(
method = heures.tv ~ "wilcox.test"
)
268
Table 18.26: ajouter les intervalles de confiance
hdv2003 |>
tbl_summary(
include = c(age, heures.tv),
statistic = ~ "{mean}"
) |>
add_ci(
statistic = ~ "entre {conf.low} et {conf.high}",
conf.level = .9,
style_fun = ~ purrr::partial(style_number, digits = 1)
)
269
Caractéristique N = 2 000 90% CI
Manquant 5
data: hdv2003$age
t = 127.12, df = 1999, p-value < 2.2e-16
alternative hypothesis: true mean is not equal to 0
95 percent confidence interval:
47.41406 48.89994
sample estimates:
mean of x
48.157
List of 10
$ statistic : Named num 127
..- attr(*, "names")= chr "t"
$ parameter : Named num 1999
..- attr(*, "names")= chr "df"
$ p.value : num 0
$ conf.int : num [1:2] 47.4 48.9
..- attr(*, "conf.level")= num 0.95
$ estimate : Named num 48.2
..- attr(*, "names")= chr "mean of x"
270
$ null.value : Named num 0
..- attr(*, "names")= chr "mean"
$ stderr : num 0.379
$ alternative: chr "two.sided"
$ method : chr "One Sample t-test"
$ data.name : chr "hdv2003$age"
- attr(*, "class")= chr "htest"
data: hdv2003$age
V = 2001000, p-value < 2.2e-16
alternative hypothesis: true location is not equal to 0
95 percent confidence interval:
47.00001 48.50007
sample estimates:
(pseudo)median
47.99996
hdv2003$age |>
wilcox.test(conf.int = TRUE) |>
purrr::pluck("conf.int")
271
[1] 47.00001 48.50007
attr(,"conf.level")
[1] 0.95
272
Ď Astuce
273
18.5 webin-R
274
19 Statistique bivariée & Tests
de comparaison
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ',')
trial |>
tbl_summary(
include = stage,
by = grade
)
275
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
library(gtsummary)
trial |>
tbl_summary(
include = c(stage, trt),
by = grade,
statistic = ~ "{p}% ({n}/{N})",
percent = "row"
) |>
add_overall(last = TRUE)
276
Table 19.2: un tableau croisé avec des pourcentages en ligne
ĺ Important
277
trial |>
tbl_cross(
row = stage,
col = grade,
percent = "row"
)
I II III Total
T Stage
T1 17 (32%) 23 (43%) 13 (25%) 53 (100%)
T2 18 (33%) 17 (31%) 19 (35%) 54 (100%)
T3 18 (42%) 11 (26%) 14 (33%) 43 (100%)
T4 15 (30%) 17 (34%) 18 (36%) 50 (100%)
Total 68 (34%) 68 (34%) 64 (32%) 200 (100%)
library(ggplot2)
ggplot(trial) +
aes(x = stage, fill = grade) +
geom_bar() +
labs(x = "T Stage", fill = "Grade", y = "Effectifs")
278
40
Grade
Effectifs
I
II
20 III
0
T1 T2 T3 T4
T Stage
library(ggplot2)
ggplot(trial) +
aes(x = stage, fill = grade) +
geom_bar(position = "dodge") +
labs(x = "T Stage", fill = "Grade", y = "Effectifs")
279
20
15 Grade
Effectifs
I
II
10
III
0
T1 T2 T3 T4
T Stage
library(ggplot2)
ggplot(trial) +
aes(x = stage, fill = grade) +
geom_bar(position = "fill") +
labs(x = "T Stage", fill = "Grade", y = "Proportion") +
scale_y_continuous(labels = scales::percent)
280
100%
75%
Grade
Proportion
I
50%
II
III
25%
0%
T1 T2 T3 T4
T Stage
281
ggplot(trial) +
aes(
x = stage, fill = grade,
label = after_stat(count)
) +
geom_bar() +
geom_text(
stat = "count",
position = position_stack(.5)
)
17 18
15
40
18 grade
count
I
17 17
23 II
20 11 III
19 18
13 14
0
T1 T2 T3 T4
stage
282
library(ggstats)
ggplot(trial) +
aes(
x = stage,
fill = grade,
by = stage,
label = scales::percent(after_stat(prop), accuracy = .1)
) +
geom_bar(position = "fill") +
geom_text(
stat = "prop",
position = position_fill(.5)
) +
scale_y_continuous(labels = scales::percent)
100%
grade
count
34.0% I
50% 31.5%
43.4% 25.6% II
III
25%
35.2% 32.6% 36.0%
24.5%
0%
T1 T2 T3 T4
stage
283
p <- ggplot(trial) +
aes(
x = stage,
y = after_stat(prop),
fill = grade,
by = grade,
label = scales::percent(after_stat(prop), accuracy = 1)
) +
geom_bar(
stat = "prop",
position = position_dodge(.9)
) +
geom_text(
aes(y = after_stat(prop) - 0.01),
stat = "prop",
position = position_dodge(.9),
vjust = "top"
) +
scale_y_continuous(labels = scales::percent)
p
34%
30%
30%
28%
26% 26%
25% 25% 25%
grade
20% 22% 22%
20% I
prop
II
16%
III
10%
0%
T1 T2 T3 T4
stage
284
p +
theme_light() +
xlab("") +
ylab("") +
labs(fill = "") +
ggtitle("Distribution selon le niveau, par grade") +
theme(
panel.grid = element_blank(),
panel.border = element_blank(),
axis.text.y = element_blank(),
axis.ticks = element_blank(),
legend.position = "top"
) +
scale_fill_brewer()
34%
30%
28%
26% 26%
25% 25% 25%
22% 22%
20%
16%
T1 T2 T3 T4
285
plus). Pour table(), on passera les deux vecteurs à croisés,
tandis que pour xtabs() on décrira le tableau attendu à l’aide
d’une formule.
table(trial$stage, trial$grade)
I II III
T1 17 23 13
T2 18 17 19
T3 18 11 14
T4 15 17 18
grade
stage I II III
T1 17 23 13
T2 18 17 19
T3 18 11 14
T4 15 17 18
grade
stage I II III Sum
T1 17 23 13 53
T2 18 17 19 54
T3 18 11 14 43
T4 15 17 18 50
Sum 68 68 64 200
286
Pour le calcul des pourcentages, le plus simple est d’avoir
recours au package {questionr} qui fournit les fonc-
tions questionr::cprop(), questionr::rprop() et
questionr::prop() qui permettent de calculer, respecti-
vement, les pourcentages en colonne, en ligne et totaux.
questionr::cprop(tab)
grade
stage I II III Ensemble
T1 25.0 33.8 20.3 26.5
T2 26.5 25.0 29.7 27.0
T3 26.5 16.2 21.9 21.5
T4 22.1 25.0 28.1 25.0
Total 100.0 100.0 100.0 100.0
questionr::rprop(tab)
grade
stage I II III Total
T1 32.1 43.4 24.5 100.0
T2 33.3 31.5 35.2 100.0
T3 41.9 25.6 32.6 100.0
T4 30.0 34.0 36.0 100.0
Ensemble 34.0 34.0 32.0 100.0
questionr::prop(tab)
grade
stage I II III Total
T1 8.5 11.5 6.5 26.5
T2 9.0 8.5 9.5 27.0
T3 9.0 5.5 7.0 21.5
T4 7.5 8.5 9.0 25.0
Total 34.0 34.0 32.0 100.0
287
19.1.4 Test du Chi² et dérivés
grade
stage I II III
T1 17 23 13
T2 18 17 19
T3 18 11 14
T4 15 17 18
chisq.test(tab)
data: tab
X-squared = 4.8049, df = 6, p-value = 0.5691
trial |>
tbl_summary(
include = stage,
by = grade
) |>
add_p()
288
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
II, N = III, N = p-
Caractéristique
I, N = 68 68 64 valeur
T Stage 0,6
T1 17 (25%) 23 (34%) 13 (20%)
T2 18 (26%) 17 (25%) 19 (30%)
T3 18 (26%) 11 (16%) 14 (22%)
T4 15 (22%) 17 (25%) 18 (28%)
data: tab
p-value = 0.5801
alternative hypothesis: two.sided
trial |>
tbl_summary(
include = stage,
by = grade
) |>
add_p(test = all_categorical() ~ "fisher.test")
289
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
II, N = III, N = p-
Caractéristique
I, N = 68 68 64 valeur
T Stage 0,6
T1 17 (25%) 23 (34%) 13 (20%)
T2 18 (26%) 17 (25%) 19 (30%)
T3 18 (26%) 11 (16%) 14 (22%)
T4 15 (22%) 17 (25%) 18 (28%)
Ĺ Note
290
trt
I(stage == "T1") Drug A Drug B Ensemble
FALSE 71.4 75.5 73.5
TRUE 28.6 24.5 26.5
Total 100.0 100.0 100.0
data: tab
X-squared = 0.24047, df = 1, p-value = 0.6239
alternative hypothesis: two.sided
95 percent confidence interval:
-0.2217278 0.1175050
sample estimates:
prop 1 prop 2
0.4761905 0.5283019
fisher.test(tab)
data: tab
p-value = 0.5263
alternative hypothesis: true odds ratio is not equal to 1
95 percent confidence interval:
0.4115109 1.5973635
sample estimates:
odds ratio
0.8125409
291
Mais le plus simple reste encore d’avoir recours à {gtsummary}
et à sa fonction gtsummary::add_difference() que l’on peut
appliquer à un tableau où le paramètre by n’a que deux moda-
lités. Pour la différence de proportions, il faut que les variables
transmises à include soit dichotomiques.
trial |>
tbl_summary(
by = trt,
include = response
) |>
add_difference()
trial |>
tbl_summary(
by = trt,
include = grade
) |>
add_difference()
292
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
trial |>
fastDummies::dummy_cols("grade") |>
tbl_summary(
by = trt,
include = starts_with("grade_"),
digits = ~ c(0, 1)
) |>
add_difference()
293
Table 19.8: différence entre proportions avec création de va-
riables dichotomiques
trial |>
tbl_summary(
include = age,
by = grade
)
294
Table 19.9: âge médian et intervalle interquartile selon le grade
trial |>
tbl_summary(
include = age,
by = grade
) |>
add_overall(last = TRUE) |>
modify_spanning_header(
all_stat_cols(stat_0 = FALSE) ~ "**Grade**"
)
295
trial |>
tbl_summary(
include = age,
by = grade,
statistic = all_continuous() ~ "{mean} ({sd})",
digits = all_continuous() ~ c(1, 1)
) |>
add_overall(last = TRUE)
ggplot(trial) +
aes(x = grade, y = age) +
geom_boxplot(fill = "lightblue") +
theme_light()
296
80
60
age
40
20
I II III
grade
Ď Astuce
ggplot(trial) +
aes(x = grade, y = age) +
geom_violin(fill = "lightblue") +
theme_light()
297
80
60
age
40
20
I II III
grade
ggplot(trial) +
aes(x = grade, y = age) +
geom_point(alpha = .25, colour = "blue") +
theme_light()
298
80
60
age
40
20
I II III
grade
ggplot(trial) +
aes(x = grade, y = age) +
geom_point(
alpha = .25,
colour = "blue",
position = position_jitter(height = 0, width = .2)
) +
theme_light()
299
80
60
age
40
20
I II III
grade
La statistique ggstats::stat_weighted_mean() de
{ggstats} permets de calculer à la volée la moyenne du
nuage de points.
ggplot(trial) +
aes(x = grade, y = age) +
geom_point(stat = "weighted_mean", colour = "blue") +
theme_light()
300
48.0
47.5
age
47.0
46.5
I II III
grade
ggplot(trial) +
aes(x = grade, y = age, colour = stage, group = stage) +
geom_line(stat = "weighted_mean") +
geom_point(stat = "weighted_mean") +
facet_grid(cols = vars(trt)) +
theme_light()
301
Drug A Drug B
55
stage
T1
50
age
T2
T3
T4
45
I II III I II III
grade
library(dplyr)
trial |>
group_by(grade) |>
summarise(
age_moy = mean(age, na.rm = TRUE),
age_med = median(age, na.rm = TRUE)
)
# A tibble: 3 x 3
grade age_moy age_med
<fct> <dbl> <dbl>
1 I 46.2 47
2 II 47.5 48.5
3 III 48.1 47
302
En base R, on peut avoir recours à tapply(). On lui indique
d’abord le vecteur sur lequel on souhaite réaliser le calcul, puis
un facteur qui indiquera les sous-groupes, puis une fonction
qui sera appliquée à chaque sous-groupe et enfin, optionnelle-
ment, des arguments additionnels qui seront transmis à cette
fonction.
I II III
46.15152 47.53226 48.11475
trial |>
tbl_summary(
include = age,
by = grade
) |>
add_p()
II, N = III, N = p-
Caractéristique
I, N = 68 68 64 valeur
Age 47 (37 – 49 (37 – 47 (38 – 0,8
56) 57) 58)
Manquant 2 6 3
303
Par défaut, pour les variables continues, un test de Kruskal-
Wallis calculé avec la fonction stats::kruskal.test() est uti-
lisé lorsqu’il y a trois groupes ou plus, et un test de Wilcoxon-
Mann-Whitney calculé avec stats::wilcox.test() (test de
comparaison des rangs) lorsqu’il n’y a que deux groupes. Au
sens strict, il ne s’agit pas de tests de comparaison des mé-
dianes mais de tests sur la somme des rangs26 . En pratique, ces 26
Si l’on a besoin spécifique-
tests sont appropriés lorsque l’on présente les médianes et les ment d’un test de comparaison
des médianes, il existe le test
intervalles inter-quartiles.
de Brown-Mood disponible dans
Si l’on affiche des moyennes, il serait plus juste d’utiliser un le package {coin} avec la fonc-
tion coin::median_test(). Atten-
test t de Student (test de comparaison des moyennes) calculé tion, il ne faut pas confondre ce
avec stats::t.test(), valable seulement si l’on compare deux test avec le test de dispersion de
moyennes. Pour tester si trois moyennes ou plus sont égales, on Mood implémenté dans la fonction
aura plutôt recours à stats::oneway.test(). stats::mood.test().
trial |>
tbl_summary(
include = age,
by = grade,
statistic = all_continuous() ~ "{mean} ({sd})"
) |>
add_p(
test = all_continuous() ~ "oneway.test"
)
304
Table 19.13: test de comparaison des moyennes
II, N = III, N = p-
Caractéristique
I, N = 68 68 64 valeur
Age 46 (15) 48 (14) 48 (14) 0,7
Manquant 2 6 3
ĺ Précision statistique
305
trial |>
tbl_summary(
include = age,
by = trt,
statistic = all_continuous() ~ "{mean} ({sd})"
) |>
add_p(
test = all_continuous() ~ "t.test",
test.args = all_continuous() ~ list(var.equal = TRUE)
)
Drug A, N Drug B, N p-
Caractéristique = 98 = 102 valeur
Age 47 (15) 47 (14) 0,8
Manquant 7 4
trial |>
tbl_summary(
include = age,
by = trt,
statistic = all_continuous() ~ "{mean} ({sd})"
) |>
add_difference()
306
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_point(colour = "blue", alpha = .25) +
theme_light()
307
2.5
2.0
Petal.Width
1.5
1.0
0.5
0.0
2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth() +
geom_point(colour = "blue", alpha = .25) +
theme_light()
308
2.5
2.0
Petal.Width
1.5
1.0
0.5
0.0
2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth(method = "lm") +
geom_point(colour = "blue", alpha = .25) +
theme_light()
309
2
Petal.Width
2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth(method = "lm") +
geom_point(colour = "blue", alpha = .25) +
theme_light() +
expand_limits(x = 0, y = -0.5)
310
2
Petal.Width
0 2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth(method = "lm", fullrange = TRUE) +
geom_point(colour = "blue", alpha = .25) +
theme_light() +
expand_limits(x = 0, y = -0.5)
311
2
Petal.Width
0 2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth(
method = "lm",
xseq = seq(0, 1, by = .1),
linetype = "dotted",
se = FALSE
) +
geom_smooth(method = "lm") +
geom_point(colour = "blue", alpha = .25) +
theme_light() +
expand_limits(x = 0, y = -0.5)
312
2
Petal.Width
0 2 4 6
Petal.Length
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_smooth(method = "lm") +
geom_point(colour = "blue", alpha = .25) +
geom_rug() +
theme_light()
313
2
Petal.Width
2 4 6
Petal.Length
cor(iris$Petal.Length, iris$Petal.Width)
[1] 0.9628654
Call:
lm(formula = Petal.Length ~ Petal.Width, data = iris)
Residuals:
314
Min 1Q Median 3Q Max
-1.33542 -0.30347 -0.02955 0.25776 1.39453
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 1.08356 0.07297 14.85 <2e-16 ***
Petal.Width 2.22994 0.05140 43.39 <2e-16 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
m |>
tbl_regression() |>
add_glance_source_note()
315
entre plusieurs variables, tant quantitatives que qualitatives.
library(GGally)
ggpairs(iris)
Sepal.Length
0.4
0.3 Corr: Corr: Corr:
0.2
0.1 −0.118 0.872*** 0.818***
0.0
Sepal.Width
4.5
4.0 Corr: Corr:
3.5
3.0
2.5 −0.428*** −0.366***
2.0
Petal.Length
6
Corr:
4
2 0.963***
Petal.Width Species
2.5
2.0
1.5
1.0
0.5
0.0
7.5
5.0
2.5
0.0
7.5
5.0
2.5
0.0
7.5
5.0
2.5
0.0
5 6 7 8 2.02.53.03.54.04.5 2 4 6 0.00.51.01.52.02.5 setosa
versicolor
virginica
316
trt age marker stage grade response death ttdeath
100
75
trt
50
25
80
Corr: −0.003 Corr: 0.124. Corr: 0.076 Corr: −0.051
60
age
40
4
Corr: 0.123. Corr: −0.048 Corr: 0.083
3
marker
2 Drug A: 0.106 Drug A: 0.146 Drug A: −0.061
1
Drug B: 0.155 Drug B: −0.230* Drug B: 0.191.
0
30
20
10
0
30
20
10
stage
0
30
20
10
0
30
20
10
0
30
20
10
0
30
grade
20
10
0
30
20
10
0
1.00
Corr: −0.220** Corr: 0.204**
0.75
response
0.50
Drug A: −0.113 Drug A: 0.086
0.25
Drug B: −0.331*** Drug B: 0.317**
0.00
1.00
Corr: −0.737***
0.75
death
0.50
Drug A: −0.714***
0.25
Drug B: −0.759***
0.00
25
20
ttdeath
15
10
0 10 20 30 40 500 10 20 30 40 50 20 40 60 80 0 1 2 3 4 0 1020300 1020300 1020300 102030 0 102030 0 102030 0 102030 0.00 0.25 0.50 0.75 1.000.00 0.25 0.50 0.75 1.00 5 10 15 20 25
19.5 webin-R
317
20 Échelles de Likert
library(tidyverse)
318
library(labelled)
niveaux <- c(
"Pas du tout d'accord",
"Plutôt pas d'accord",
"Ni d'accord, ni pas d'accord",
"Plutôt d'accord",
"Tout à fait d'accord"
)
set.seed(42)
df <-
tibble(
groupe = sample(c("A", "B"), 150, replace = TRUE),
q1 = sample(niveaux, 150, replace = TRUE),
q2 = sample(niveaux, 150, replace = TRUE, prob = 5:1),
q3 = sample(niveaux, 150, replace = TRUE, prob = 1:5),
q4 = sample(niveaux, 150, replace = TRUE, prob = 1:5),
q5 = sample(c(niveaux, NA), 150, replace = TRUE),
q6 = sample(niveaux, 150, replace = TRUE, prob = c(1, 0, 1, 1, 0))
) |>
mutate(across(q1:q6, ~ factor(.x, levels = niveaux))) |>
set_variable_labels(
q1 = "Première question",
q2 = "Seconde question",
q3 = "Troisième question",
q4 = "Quatrième question",
q5 = "Cinquième question",
q6 = "Sixième question"
)
library(gtsummary)
df |>
tbl_summary(include = q1:q6)
319
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Characteristic N = 150
Première question
Pas du tout d’accord 39 (26%)
Plutôt pas d’accord 32 (21%)
Ni d’accord, ni pas d’accord 25 (17%)
Plutôt d’accord 30 (20%)
Tout à fait d’accord 24 (16%)
Seconde question
Pas du tout d’accord 56 (37%)
Plutôt pas d’accord 44 (29%)
Ni d’accord, ni pas d’accord 19 (13%)
Plutôt d’accord 26 (17%)
Tout à fait d’accord 5 (3.3%)
Troisième question
Pas du tout d’accord 8 (5.3%)
Plutôt pas d’accord 17 (11%)
Ni d’accord, ni pas d’accord 29 (19%)
Plutôt d’accord 43 (29%)
Tout à fait d’accord 53 (35%)
Quatrième question
Pas du tout d’accord 11 (7.3%)
Plutôt pas d’accord 19 (13%)
Ni d’accord, ni pas d’accord 31 (21%)
Plutôt d’accord 40 (27%)
Tout à fait d’accord 49 (33%)
Cinquième question
Pas du tout d’accord 33 (26%)
Plutôt pas d’accord 25 (20%)
Ni d’accord, ni pas d’accord 28 (22%)
Plutôt d’accord 25 (20%)
Tout à fait d’accord 16 (13%)
Unknown 23
Sixième question
Pas du tout d’accord 50 (33%)
Plutôt pas d’accord 0 (0%)
320
Characteristic N = 150
Ni d’accord, ni pas d’accord 50 (33%)
Plutôt d’accord 50 (33%)
Tout à fait d’accord 0 (0%)
ĺ Important
library(bstfun)
trial
df |>
tbl_likert(
include = q1:q6
)
321
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Ni
Pas du Plutôt d’accord, Tout à
tout pas ni pas Plutôt fait
Characteristic
d’accord d’accord d’accord d’accordd’accord
Première 39 32 25 (17%) 30 24
ques- (26%) (21%) (20%) (16%)
tion
Seconde 56 44 19 (13%) 26 5 (3.3%)
ques- (37%) (29%) (17%)
tion
Troisième8 (5.3%) 17 29 (19%) 43 53
ques- (11%) (29%) (35%)
tion
Quatrième 11 19 31 (21%) 40 49
ques- (7.3%) (13%) (27%) (33%)
tion
Cinquième 33 25 28 (22%) 25 16
ques- (26%) (20%) (20%) (13%)
tion
Sixième 50 0 (0%) 50 (33%) 50 0 (0%)
ques- (33%) (33%)
tion
df |>
tbl_likert(
include = q1:q6,
statistic = ~ "{p}%"
) |>
add_n() |>
add_continuous_stat(score_values = -2:2)
322
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Pas Ni
du Plutôt d’accord, Tout
tout pas ni pas Plutôt à fait
Characteristic
N d’accordd’accordd’accord d’accordd’accordMean
Première
150 26% 21% 17% 20% 16% -
ques- 0.21
tion
Seconde150 37% 29% 13% 17% 3.3% -
ques- 0.80
tion
Troisième
150 5.3% 11% 19% 29% 35% 0.77
ques-
tion
Quatrième
150 7.3% 13% 21% 27% 33% 0.65
ques-
tion
127 26%
Cinquième 20% 22% 20% 13% -
ques- 0.27
tion
Sixième150 33% 0% 33% 33% 0% -
ques- 0.33
tion
library(ggstats)
gglikert(df, include = q1:q6)
323
Première question 47% 26% 21% 17% 20% 16% 36%
50% 0% 50%
Pas du tout d'accord Plutôt pas d'accord Ni d'accord, ni pas d'accord Plutôt d'accord Tout à fait d'accord
df |>
gglikert(
include = q1:q6,
totals_include_center = TRUE,
sort = "ascending"
) +
guides(
fill = guide_legend(nrow = 2)
)
324
Seconde question 73% 37% 29% 13% 17% 27%
50% 0% 50%
df |>
gglikert(
include = q1:q6,
facet_cols = vars(groupe)
)
A B
Sixième question 28% 28% 29% 43% 43%38% 38% 37% 25% 25%
Pas du tout d'accord Plutôt pas d'accord Ni d'accord, ni pas d'accord Plutôt d'accord Tout à fait d'accord
325
df |>
gglikert(
include = q1:q6,
y = "groupe",
facet_rows = vars(.question),
facet_label_wrap = 15
)
PremièreSeconde
questionquestionquestionquestionquestionquestion
A 51% 30% 20% 20% 16% 13% 29%
B 44% 22% 22% 14% 23% 19% 42%
A 65% 29% 36% 14% 19% 20%
B 68% 44% 23% 11% 16% 21%
Troisième
A 10% 6% 17% 28% 45% 72%
B 22% 6% 16% 21% 30% 27% 57%
Quatrième
A 22% 7% 14% 22% 33% 23% 57%
B 19% 7%11% 20% 21% 41% 62%
Cinquième
A 41% 21% 21% 25% 19% 14% 33%
B 50% 31% 19% 19% 20% 11% 31%
Sixième
A 28% 28% 29% 43% 43%
B 38% 38% 37% 25% 25%
50% 0% 50%
Pas du tout d'accord Plutôt pas d'accord Ni d'accord, ni pas d'accord Plutôt d'accord Tout à fait d'accord
df |>
gglikert_stacked(
include = q1:q6,
sort = "ascending",
add_median_line = TRUE
)
326
Seconde question 37% 29% 13% 17%
Pas du tout d'accord Plutôt pas d'accord Ni d'accord, ni pas d'accord Plutôt d'accord Tout à fait d'accord
327
21 Régression linéaire
library(tidyverse)
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_point(colour = "blue", alpha = .25) +
labs(x = "Longueur", y = "Largeur") +
theme_light()
328
2.5
2.0
1.5
Largeur
1.0
0.5
0.0
2 4 6
Longueur
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_point(colour = "blue", alpha = .25) +
geom_smooth(method = "lm") +
labs(x = "Longueur", y = "Largeur") +
theme_light()
329
2
Largeur
2 4 6
Longueur
Call:
lm(formula = Petal.Width ~ Petal.Length, data = iris)
Coefficients:
(Intercept) Petal.Length
-0.3631 0.4158
330
Le résultat comporte deux coefficients. Le premier, d’une valeur
de 0, 4158, est associé à la variable Petal.Length et indique la
pente de la courbe (on parle de slope en anglais). Le second,
d’une valeur de −0, 3631, représente l’ordonnée à l’origine (in-
tercept en anglais), c’est-à-dire la valeur estimée de Petal.Width
lorsque Petal.Length vaut 0. Nous pouvons rendre cela plus vi-
sible en élargissant notre graphique.
ggplot(iris) +
aes(x = Petal.Length, y = Petal.Width) +
geom_point(colour = "blue", alpha = .25) +
geom_abline(
intercept = mod$coefficients[1],
slope = mod$coefficients[2],
linewidth = 1,
colour = "red"
) +
geom_vline(xintercept = 0, linewidth = 1, linetype = "dotted") +
labs(x = "Longueur", y = "Largeur") +
expand_limits(x = 0, y = -1) +
theme_light()
2
Largeur
−1
0 2 4 6
Longueur
331
Le modèle linéaire calculé estime donc que le relation entre nos
deux variables peut s’écrire sous la forme suivante :
Ď Astuce
332
modèle.
Call:
lm(formula = Petal.Width ~ Petal.Length - 1, data = iris)
Coefficients:
Petal.Length
0.3365
library(labelled)
iris %>% look_for("Species")
Call:
333
lm(formula = Petal.Width ~ Species, data = iris)
Coefficients:
(Intercept) Speciesversicolor Speciesvirginica
0.246 1.080 1.780
mod %>%
tbl_regression(intercept = TRUE)
iris %>%
group_by(Species) %>%
summarise(mean(Petal.Width))
# A tibble: 3 x 2
Species `mean(Petal.Width)`
<fct> <dbl>
1 setosa 0.246
2 versicolor 1.33
3 virginica 2.03
334
Comme on le voit, l’intercept nous indique donc la moyenne
observée pour l’espèce de référence (0, 246).
Le coefficient associé à versicolor correspond à la différence
par rapport à la référence (ici +1, 080). Comme vous pouvez le
constater, il s’agit de la différence entre la moyenne observée
pour versicolor (1, 326) et celle de la référence setosa (0, 246) :
1, 326 − 0, 246 = 1, 080.
Ce coefficient est significativement différent de 0 (p<0,001), in-
diquant que la largeur des pétales diffère significativement entre
les deux espèces.
Ď Astuce
Call:
lm(formula = Petal.Width ~ Species - 1, data = iris)
Coefficients:
Speciessetosa Speciesversicolor Speciesvirginica
0.246 1.326 2.026
335
21.3 Modèle à plusieurs variables explicatives
Call:
lm(formula = Petal.Width ~ Petal.Length + Sepal.Width + Sepal.Length +
Species, data = iris)
Coefficients:
(Intercept) Petal.Length Sepal.Width Sepal.Length
-0.47314 0.24220 0.24220 -0.09293
Speciesversicolor Speciesvirginica
0.64811 1.04637
mod %>%
tbl_regression(intercept = TRUE)
336
Characteristic Beta 95% CI p-value
Sepal.Width 0.24 0.15, 0.34 <0.001
Sepal.Length -0.09 -0.18, 0.00 0.039
Species
setosa — —
versicolor 0.65 0.40, 0.89 <0.001
virginica 1.0 0.72, 1.4 <0.001
library(ggstats)
ggcoef_model(mod)
Petal.Length
(p<0.001***)
Sepal.Width
(p<0.001***)
Sepal.Length
(p=0.039*)
Species
setosa
versicolor (p<0.001***)
virginica (p<0.001***)
337
22 Régression logistique
binaire
338
d’heures passées à regarder la télévision par jour sur la proba-
bilité de pratiquer un sport.
En premier lieu, il importe de vérifier, par exemple avec
labelled::look_for(), que notre variable d’intérêt (ici
sport) est correctement codée, c’est-à-dire que la première
modalité correspondent à la référence (soit ne pas avoir vécu
l’évènement d’intérêt) et que la seconde modalité corresponde
au fait d’avoir vécu l’évènement.
library(labelled)
d |> look_for("sport")
339
tous les coefficients sont calculés par rapport à la modalité de
référence (cf. Section 21.2). Il importe donc de choisir une mo-
dalité de référence qui fasse sens afin de faciliter l’interprétation.
Par ailleurs, ce choix doit dépendre de la manière dont on sou-
haite présenter les résultats (le data storytelling est essentiel).
De manière générale on évitera de choisir comme référence une
modalité peu représentée dans l’échantillon ou bien une moda-
lité correspondant à une situation atypique.
Prenons l’exemple de la variable sexe. Souhaite-t-on connaitre
l’effet d’être une femme par rapport au fait d’être un homme
ou bien l’effet d’être un homme par rapport au fait d’être une
femme ? Si l’on opte pour le second, alors notre modalité de ré-
férence sera le sexe féminin. Comme est codée cette variable ?
d |> look_for("sexe")
library(tidyverse)
d <- d |>
mutate(sexe = sexe |> fct_relevel("Femme"))
n % val%
Femme 1101 55 55
Homme 899 45 45
Données labellisées
Si l’on utilise des données labellisées (voir Chapitre 12), nos
variables catégorielles seront stockées sous la forme d’un
340
vecteur numérique avec des étiquettes. Il sera donc nécessaire
de convertir ces variables en facteurs, tout simplement avec
labelled::to_factor() ou labelled::unlabelled().
Les variables age et heures.tv sont des variables quantitatives.
Il importe de vérifier qu’elles sont bien enregistrées en tant que
variables numériques. En effet, il arrive parfois que dans le fi-
chier source les variables quantitatives soient renseignées sous
forme de valeur textuelle et non sous forme numérique.
d <- d |>
mutate(
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
)
)
d$groupe_ages |> questionr::freq()
n % val%
18-24 ans 169 8.5 8.5
341
25-44 ans 706 35.3 35.3
45-64 ans 745 37.2 37.2
65 ans et plus 380 19.0 19.0
n % val%
N'a jamais fait d'etudes 39 2.0 2.1
A arrete ses etudes, avant la derniere annee d'etudes primaires 86 4.3 4.6
Derniere annee d'etudes primaires 341 17.0 18.1
1er cycle 204 10.2 10.8
2eme cycle 183 9.2 9.7
Enseignement technique ou professionnel court 463 23.2 24.5
Enseignement technique ou professionnel long 131 6.6 6.9
Enseignement superieur y compris technique superieur 441 22.0 23.4
NA 112 5.6 NA
d <- d |>
mutate(
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
)
)
342
d$etudes |> questionr::freq()
n % val%
Primaire 466 23.3 24.7
Secondaire 387 19.4 20.5
Technique / Professionnel 594 29.7 31.5
Supérieur 441 22.0 23.4
NA 112 5.6 NA
d <- d |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
relig = "Rapport à la religion",
heures.tv = "Heures de télévision / jour"
)
343
Ĺ Code récapitulatif (préparation des données)
344
22.2 Statistiques descriptives
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",", big.mark = " ")
d |>
tbl_summary(
by = sport,
include = c(sexe, groupe_ages, etudes, relig, heures.tv)
) |>
add_overall(last = TRUE) |>
add_p() |>
bold_labels() |>
modify_spanning_header(
update = all_stat_cols() ~ "**Pratique un sport ?**"
)
345
Non, N Oui, N Total, N p-
Caractéristique = 1 277 = 723 = 2 000 valeur
Groupe <0,001
d’âges
18-24 ans 58 (4,5%) 111 169
(15%) (8,5%)
25-44 ans 359 347 706 (35%)
(28%) (48%)
45-64 ans 541 204 745 (37%)
(42%) (28%)
65 ans et plus 319 61 (8,4%) 380 (19%)
(25%)
Niveau <0,001
d’études
Primaire 416 50 (6,9%) 466 (23%)
(33%)
Secondaire 270 117 387 (19%)
(21%) (16%)
Technique / 378 216 594 (30%)
Professionnel (30%) (30%)
Supérieur 186 255 441 (22%)
(15%) (35%)
Non 27 (2,1%) 85 (12%) 112
documenté (5,6%)
Rapport à la 0,14
religion
Pratiquant 182 84 (12%) 266 (13%)
regulier (14%)
Pratiquant 295 147 442 (22%)
occasionnel (23%) (20%)
Appartenance 473 287 760 (38%)
sans pratique (37%) (40%)
Ni croyance ni 239 160 399 (20%)
appartenance (19%) (22%)
Rejet 60 (4,7%) 33 (4,6%) 93 (4,7%)
NSP ou NVPR 28 (2,2%) 12 (1,7%) 40 (2,0%)
Heures de 2,00 (1,00 2,00 (1,00 2,00 (1,00 <0,001
télévision / – 3,00) – 3,00) – 3,00)
jour
Manquant 2 3 5
346
22.3 Calcul de la régression logistique binaire
mod |>
tbl_regression(intercept = TRUE) |>
bold_labels()
347
Caractéristique log(OR) 95% IC p-valeur
45-64 ans -1,1 -1,6 – -0,62 <0,001
65 ans et plus -1,4 -1,9 – -0,85 <0,001
Niveau d’études
Primaire — —
Secondaire 0,95 0,57 – 1,3 <0,001
Technique / 1,0 0,68 – 1,4 <0,001
Professionnel
Supérieur 1,9 1,5 – 2,3 <0,001
Non documenté 2,2 1,5 – 2,8 <0,001
Rapport à la
religion
Pratiquant regulier — —
Pratiquant occasionnel -0,02 -0,39 – >0,9
0,35
Appartenance sans -0,01 -0,35 – >0,9
pratique 0,34
Ni croyance ni -0,22 -0,59 – 0,3
appartenance 0,16
Rejet -0,38 -0,95 – 0,2
0,17
NSP ou NVPR -0,08 -0,92 – 0,8
0,70
Heures de télévision -0,12 -0,19 – <0,001
/ jour -0,06
348
selon l’échelle logit. Retraduisons cela en probabilité classique
avec la fonction logit inverse.
[1] 0.3100255
logit_inverse(-0.80 + 0.44)
[1] 0.4109596
[1] 0.3543437
349
individu3 <- d[1, ]
individu3$sexe[1] <- "Homme"
individu3$groupe_ages[1] <- "18-24 ans"
individu3$etudes[1] <- "Primaire"
individu3$relig[1] <- "Pratiquant regulier"
individu3$heures.tv[1] <- 2
library(breakDown)
logit <- function(x) exp(x) / (1 + exp(x))
plot(
broken(mod, individu3, predict.function = betas),
trans = logit
) +
scale_y_continuous(
labels = scales::label_percent(),
breaks = 0:5/5,
limits = c(0, 1)
)
final_prognosis −0.146
etudes = Primaire 0
heures.tv = 2 −0.057
(Intercept) −0.19
350
22.5 La notion d’odds ratio
Ď Astuce
questionr::odds.ratio(.75, 1/3)
[1] 6
L’odds ratio est donc égal à 1 si les deux côtes sont iden-
tiques, est supérieur à 1 si le cheval A une probabilité
supérieure à celle du cheval B, et inférieur à 1 si c’est
probabilité est inférieure.
351
On le voit, par construction, l’odds ratio de B par rapport
à A est l’inverse de celui de A par rapport à B : 𝑂𝑅𝐵/𝐴 =
1/𝑂𝑅𝐴/𝐵 .
mod |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
352
Caractéristique OR 95% IC p-valeur
Rejet 0,68 0,39 – 1,19 0,2
NSP ou NVPR 0,92 0,40 – 2,02 0,8
Heures de télévision / jour 0,89 0,83 – 0,95 <0,001
mod |>
ggstats::ggcoef_model(exponentiate = TRUE)
Sexe Femme
Homme (p<0.001***)
Groupe d'âges 18−24 ans
25−44 ans (p=0.065)
45−64 ans (p<0.001***)
65 ans et plus (p<0.001***)
Niveau d'études Primaire
Secondaire (p<0.001***)
Technique / Professionnel (p<0.001***)
Supérieur (p<0.001***)
Non documenté (p<0.001***)
Rapport à la religion Pratiquant regulier
Pratiquant occasionnel (p=0.908)
Appartenance sans pratique (p=0.969)
Ni croyance ni appartenance (p=0.265)
Rejet (p=0.180)
NSP ou NVPR (p=0.838)
Heures de télévision / jour (p<0.001***)
0.3 1.0 3.0 10.0
OR
mod |>
ggstats::ggcoef_table(exponentiate = TRUE)
353
OR
95% CIp
Sexe Femme 1.0
Homme 1.6
1.3,<0.001
1.9
Groupe d'âges 18−24 ans 1.0
25−44 ans 0.7
0.4, 0.065
1.0
45−64 ans 0.3
0.2,<0.001
0.5
65 ans et plus 0.3
0.1,<0.001
0.4
Niveau d'études Primaire 1.0
Secondaire 2.6
1.8,<0.001
3.8
Technique / Professionnel 2.9
2.0,<0.001
4.2
Supérieur 6.6
4.6,<0.001
9.8
Non documenté 8.6
4.5, <0.001
16.6
Rapport à la religion Pratiquant regulier 1.0
Pratiquant occasionnel 1.0
0.7, 0.908
1.4
Appartenance sans pratique 1.0
0.7, 0.969
1.4
Ni croyance ni appartenance 0.8
0.6, 0.265
1.2
Rejet 0.7
0.4, 0.180
1.2
NSP ou NVPR 0.9
0.4, 0.838
2.0
Heures de télévision / jour 0.9
0.8,<0.001
0.9
0.3 1.03.010.0
OR
Ĺ Note
¾ Mise en garde
354
choses égales par ailleurs). Une telle formulation corres-
pond à un prevalence ratio (rapport des prévalences en
français) ou risk ratio (rapport des risques), à savoir divi-
ser la probabilité de faire du sport des hommes par celle
des femmes, 𝑝ℎ𝑜𝑚𝑚𝑒𝑠 /𝑝𝑓𝑒𝑚𝑚𝑒𝑠 . Or, cela ne correspond
pas à la formule de l’odds ratio, à savoir (𝑝ℎ𝑜𝑚𝑚𝑒𝑠 /(1 −
𝑝ℎ𝑜𝑚𝑚𝑒𝑠 ))/(𝑝𝑓𝑒𝑚𝑚𝑒𝑠 /(1 − 𝑝𝑓𝑒𝑚𝑚𝑒𝑠 )).
Lorsque le phénomène étudié est rare et donc que les pro-
babilités sont faibles (inférieures à quelques pour-cents),
alors il est vrai que les odds ratio sont approximativement
égaux aux prevalence ratios. Mais ceci n’est plus du tout
vrai pour des phénomènes plus fréquents.
355
bold_labels()
Caractéristique log(OR) ET
Sexe
Femme — —
Homme 0,44*** 0,106
Groupe d’âges
18-24 ans — —
25-44 ans -0,42 0,228
45-64 ans -1,1*** 0,238
65 ans et plus -1,4*** 0,274
Niveau d’études
Primaire — —
Secondaire 0,95*** 0,197
Technique / Professionnel 1,0*** 0,190
Supérieur 1,9*** 0,195
Non documenté 2,2*** 0,330
Rapport à la religion
Pratiquant regulier — —
Pratiquant occasionnel -0,02 0,189
Appartenance sans pratique -0,01 0,175
Ni croyance ni appartenance -0,22 0,193
Rejet -0,38 0,286
NSP ou NVPR -0,08 0,411
Heures de télévision / jour -0,12*** 0,034
356
modelsummary::modelsummary() n’affiche pas les modalités
de référence, ni les étiquettes de variable.
heures.tv
religNSP ou NVPR
religRejet
religNi croyance ni appartenance
religAppartenance sans pratique
religPratiquant occasionnel
etudesNon documenté
etudesSupérieur
etudesTechnique / Professionnel
etudesSecondaire
groupe_ages65 ans et plus
groupe_ages45−64 ans
groupe_ages25−44 ans
sexeHomme
(Intercept)
−2 −1 0 1 2 3
Coefficient estimates and 95% confidence intervals
mod |>
modelsummary::modelplot(exponentiate = TRUE) +
ggplot2::scale_x_log10()
357
Table 22.5: Présentation des facteurs associés à la pratique d’un
sport avec modelsummary()
(1)
(Intercept) −0.798*
(0.324)
sexeHomme 0.440***
(0.106)
groupe_ages25-44 ans −0.420+
(0.228)
groupe_ages45-64 ans −1.085***
(0.238)
groupe_ages65 ans et plus −1.381***
(0.274)
etudesSecondaire 0.951***
(0.197)
etudesTechnique / Professionnel 1.049***
(0.190)
etudesSupérieur 1.892***
(0.195)
etudesNon documenté 2.150***
(0.330)
religPratiquant occasionnel −0.022
(0.189)
religAppartenance sans pratique −0.007
(0.175)
religNi croyance ni appartenance −0.215
(0.193)
religRejet −0.384
(0.286)
religNSP ou NVPR −0.084
(0.411)
heures.tv −0.121***
(0.034)
Num.Obs. 1995
AIC 2236.2
BIC 2320.1
Log.Lik. −1103.086
F 21.691
RMSE 0.43
+ p < 0.1, * p < 0.05, ** p < 0.01, *** p < 0.001
358
heures.tv
religNSP ou NVPR
religRejet
religNi croyance ni appartenance
religAppartenance sans pratique
religPratiquant occasionnel
etudesNon documenté
etudesSupérieur
etudesTechnique / Professionnel
etudesSecondaire
groupe_ages65 ans et plus
groupe_ages45−64 ans
groupe_ages25−44 ans
sexeHomme
(Intercept)
0.3 1.0 3.0 10.0
Coefficient estimates and 95% confidence intervals
mod |>
tbl_regression(
exponentiate = TRUE,
add_pairwise_contrasts = TRUE
) |>
bold_labels()
mod |>
ggstats::ggcoef_model(
exponentiate = TRUE,
add_pairwise_contrasts = TRUE,
pairwise_variables = c("groupe_ages", "etudes")
)
360
Table 22.6: Facteurs associés à la pratique d’un sport (pairwise
contrasts)
361
Femme
Sexe Homme (p<0.001***)
(25−44 ans) / (18−24 ans) (p=0.253)
Groupe d'âges (45−64 ans) / (18−24 ans) (p<0.001***)
(45−64 ans) / (25−44 ans) (p<0.001***)
65 ans et plus / (18−24 ans) (p<0.001***)
65 ans et plus / (25−44 ans) (p<0.001***)
65 ans et plus / (45−64 ans) (p=0.335)
Secondaire / Primaire (p<0.001***)
Niveau d'études (Technique / Professionnel) / Primaire (p<0.001***)
(Technique / Professionnel) / Secondaire (p=0.961)
Supérieur / Primaire (p<0.001***)
Supérieur / Secondaire (p<0.001***)
Supérieur / (Technique / Professionnel) (p<0.001***)
Non documenté / Primaire (p<0.001***)
Non documenté / Secondaire (p<0.001***)
Non documenté / (Technique / Professionnel) (p=0.001**)
Non documenté / Supérieur (p=0.905)
Pratiquant regulier
Rapport à la religion Pratiquant occasionnel (p=0.908)
Appartenance sans pratique (p=0.969)
Ni croyance ni appartenance (p=0.265)
Rejet (p=0.180)
NSP ou NVPR (p=0.838)
Heures de télévision / jour (p<0.001***)
0.1
1.0
10.0
OR
car::Anova(mod)
Response: sport
LR Chisq Df Pr(>Chisq)
sexe 17.309 1 3.176e-05 ***
362
groupe_ages 52.803 3 2.020e-11 ***
etudes 123.826 4 < 2.2e-16 ***
relig 4.232 5 0.5165401
heures.tv 13.438 1 0.0002465 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Ĺ Note
363
Table 22.7: Ajout des p-valeurs globales
364
interactions dans un prochain chapitre, cf. Chapitre 26).
En présence d’interactions, il est conseillé d’avoir plutôt
recours au type III. Cependant, en toute rigueur, pour
utiliser le type III, il faut que les variables catégorielles
soient codées en utilisant un contrastes dont la somme est
nulle (un contraste de type somme ou polynomial). Or,
par défaut, les variables catégorielles sont codées avec un
contraste de type traitement (nous aborderons les diffé-
rents types de contrastes plus tard, cf. Chapitre 25).
Par défaut, car::Anova() utilise le type II et
gtsummary::add_global_p() le type III. Dans les deux
cas, il est possible de préciser le type de test avec type =
"II" ou type = "III".
Dans le cas de notre exemple, un modèle simple sans in-
teraction, le type de test ne change pas les résultats.
d |>
tbl_uvregression(
y = sport,
include = c(sexe, groupe_ages, etudes, relig, heures.tv),
method = glm,
method.args = list(family = binomial),
365
Table 22.8: Régressions logistiques univariées
exponentiate = TRUE
) |>
bold_labels()
366
22.10 Présenter l’ensemble des résultats
dans un même tableau
tbl_desc <-
d |>
tbl_summary(
by = sport,
include = c(sexe, groupe_ages, etudes, relig, heures.tv),
statistic = all_categorical() ~ "{p}% ({n}/{N})",
percent = "row",
digits = all_categorical() ~ c(1, 0, 0)
) |>
modify_column_hide("stat_1") |>
modify_header("stat_2" ~ "**Pratique d'un sport**")
tbl_uni <-
d |>
tbl_uvregression(
y = sport,
include = c(sexe, groupe_ages, etudes, relig, heures.tv),
method = glm,
method.args = list(family = binomial),
exponentiate = TRUE
) |>
modify_column_hide("stat_n")
tbl_multi <-
mod |>
tbl_regression(exponentiate = TRUE)
367
Table 22.9: tableau synthétique de l’analyse
"**Régressions univariées**",
"**Régression multivariée**"
)
) |>
bold_labels()
368
R/analyses/ressources/flipbook-regression-logistique.html
22.11 webin-R
369
23 Sélection pas à pas d’un
modèle
370
library(tidyverse)
library(labelled)
library(gtsummary)
theme_gtsummary_language(
"fr",
decimal.mark = ",",
big.mark = " "
)
d <-
hdv2003 |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
371
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
relig = "Rapport à la religion",
lecture.bd = "Lit des bandes dessinées ?"
)
AIC(mod)
[1] 2257.101
372
mod2 <- step(mod)
Start: AIC=2257.1
sport ~ sexe + groupe_ages + etudes + relig + lecture.bd
Df Deviance AIC
- relig 5 2231.9 2251.9
- lecture.bd 1 2227.9 2255.9
<none> 2227.1 2257.1
- sexe 1 2245.6 2273.6
- groupe_ages 3 2280.1 2304.1
- etudes 4 2375.5 2397.5
Step: AIC=2251.95
sport ~ sexe + groupe_ages + etudes + lecture.bd
Df Deviance AIC
- lecture.bd 1 2232.6 2250.6
<none> 2231.9 2251.9
- sexe 1 2248.8 2266.8
- groupe_ages 3 2282.1 2296.1
- etudes 4 2380.5 2392.5
Step: AIC=2250.56
sport ~ sexe + groupe_ages + etudes
Df Deviance AIC
<none> 2232.6 2250.6
- sexe 1 2249.2 2265.2
- groupe_ages 3 2282.5 2294.5
- etudes 4 2385.2 2395.2
373
Deviance) et donc une baisse de la vraisemblance du modèle,
mais cela est compensé par la réduction du nombre de degrés
de liberté.
Le processus est maintenant répété. À la seconde étape, suppri-
mer lecture.bd permettrait de diminuer encore l’AIC à 2250,6
et cette variable est supprimée.
À la troisième étape, tout retrait d’une variable additionnelle
reviendrait à augmenter l’AIC.
Lors de la seconde étape, toute suppression d’une autre variable
ferait augmenter l’AIC. La procédure s’arrête donc.
L’objet mod2 renvoyé par step() est le modèle final.
mod2
Coefficients:
(Intercept) sexeHomme
-1.2815 0.4234
groupe_ages25-44 ans groupe_ages45-64 ans
-0.3012 -0.9261
groupe_ages65 ans et plus etudesSecondaire
-1.2696 0.9670
etudesTechnique / Professionnel etudesSupérieur
1.0678 1.9955
etudesNon documenté
2.3192
374
Analysis of Deviance Table
Ď Astuce
library(MASS)
select
select
Start: AIC=2257.1
sport ~ sexe + groupe_ages + etudes + relig + lecture.bd
375
Df Deviance AIC
- relig 5 2231.9 2251.9
- lecture.bd 1 2227.9 2255.9
<none> 2227.1 2257.1
- sexe 1 2245.6 2273.6
- groupe_ages 3 2280.1 2304.1
- etudes 4 2375.5 2397.5
Step: AIC=2251.95
sport ~ sexe + groupe_ages + etudes + lecture.bd
Df Deviance AIC
- lecture.bd 1 2232.6 2250.6
<none> 2231.9 2251.9
- sexe 1 2248.8 2266.8
- groupe_ages 3 2282.1 2296.1
- etudes 4 2380.5 2392.5
Step: AIC=2250.56
sport ~ sexe + groupe_ages + etudes
Df Deviance AIC
<none> 2232.6 2250.6
- sexe 1 2249.2 2265.2
- groupe_ages 3 2282.5 2294.5
- etudes 4 2385.2 2395.2
library(ggstats)
ggcoef_compare(
list("modèle complet" = mod, "modèle réduit" = mod2),
exponentiate = TRUE
)
376
Femme
Sexe Homme
18−24 ans
Groupe d'âges 25−44 ans
45−64 ans
65 ans et plus
Primaire
Niveau d'études Secondaire
Technique / Professionnel
Supérieur
Non documenté
Pratiquant regulier
Rapport à la religion Pratiquant occasionnel
Appartenance sans pratique
Ni croyance ni appartenance
Rejet
NSP ou NVPR
Non
Lit des bandes dessinées ? Oui
0.3 1.0 3.0 10.0
OR
ggcoef_compare(
list("modèle complet" = mod, "modèle réduit" = mod2),
type = "faceted",
exponentiate = TRUE
)
377
23.4 Sélection pas à pas ascendante
Start: AIC=2619.11
sport ~ 1
Df Deviance AIC
+ etudes 4 2294.9 2304.9
+ groupe_ages 3 2405.4 2413.4
+ sexe 1 2600.2 2604.2
+ lecture.bd 1 2612.7 2616.7
<none> 2617.1 2619.1
+ relig 5 2608.8 2620.8
Step: AIC=2304.92
sport ~ etudes
378
Df Deviance AIC
+ groupe_ages 3 2249.2 2265.2
+ sexe 1 2282.5 2294.5
<none> 2294.9 2304.9
+ lecture.bd 1 2294.7 2306.7
+ relig 5 2293.0 2313.0
Step: AIC=2265.17
sport ~ etudes + groupe_ages
Df Deviance AIC
+ sexe 1 2232.6 2250.6
<none> 2249.2 2265.2
+ lecture.bd 1 2248.8 2266.8
+ relig 5 2246.0 2272.0
Step: AIC=2250.56
sport ~ etudes + groupe_ages + sexe
Df Deviance AIC
<none> 2232.6 2250.6
+ lecture.bd 1 2231.9 2251.9
+ relig 5 2227.9 2255.9
Ď Astuce
379
mod3 <- step(
mod_vide,
scope = list(
upper = ~ sexe + groupe_ages + etudes + relig + lecture.bd
)
)
Start: AIC=2619.11
sport ~ 1
Df Deviance AIC
+ etudes 4 2294.9 2304.9
+ groupe_ages 3 2405.4 2413.4
+ sexe 1 2600.2 2604.2
+ lecture.bd 1 2612.7 2616.7
<none> 2617.1 2619.1
+ relig 5 2608.8 2620.8
Step: AIC=2304.92
sport ~ etudes
Df Deviance AIC
+ groupe_ages 3 2249.2 2265.2
+ sexe 1 2282.5 2294.5
<none> 2294.9 2304.9
+ lecture.bd 1 2294.7 2306.7
+ relig 5 2293.0 2313.0
- etudes 4 2617.1 2619.1
Step: AIC=2265.17
sport ~ etudes + groupe_ages
Df Deviance AIC
+ sexe 1 2232.6 2250.6
<none> 2249.2 2265.2
+ lecture.bd 1 2248.8 2266.8
+ relig 5 2246.0 2272.0
- groupe_ages 3 2294.9 2304.9
- etudes 4 2405.4 2413.4
380
Step: AIC=2250.56
sport ~ etudes + groupe_ages + sexe
Df Deviance AIC
<none> 2232.6 2250.6
+ lecture.bd 1 2231.9 2251.9
+ relig 5 2227.9 2255.9
- sexe 1 2249.2 2265.2
- groupe_ages 3 2282.5 2294.5
- etudes 4 2385.2 2395.2
Start: AIC=2257.1
sport ~ sexe + groupe_ages + etudes + relig + lecture.bd
381
Df Deviance AIC
- relig 5 2231.9 2251.9
<none> 2227.1 2257.1
- sexe 1 2245.6 2273.6
- groupe_ages 3 2280.1 2304.1
- etudes 4 2375.5 2397.5
Step: AIC=2251.95
sport ~ sexe + groupe_ages + etudes + lecture.bd
Df Deviance AIC
<none> 2231.9 2251.9
- sexe 1 2248.8 2266.8
- groupe_ages 3 2282.1 2296.1
- etudes 4 2380.5 2392.5
mod4$formula
382
lesquelles des données sont manquantes. Dès lors, pour obte-
nir le nombre exact d’observations incluses dans le modèle, on
peut utiliser la syntaxe mod |> model.matrix() |> nrow(),
model.matrix() renvoyant la matrice de données ayant servi
au calcul du modèle et nrow() le nombre de lignes.
Start: AIC=2341.11
sport ~ sexe + groupe_ages + etudes + relig + lecture.bd
Df Deviance AIC
- relig 5 2231.9 2308.0
- lecture.bd 1 2227.9 2334.3
<none> 2227.1 2341.1
- sexe 1 2245.6 2352.0
- groupe_ages 3 2280.1 2371.3
- etudes 4 2375.5 2459.1
Step: AIC=2307.96
sport ~ sexe + groupe_ages + etudes + lecture.bd
Df Deviance AIC
- lecture.bd 1 2232.6 2301.0
<none> 2231.9 2308.0
- sexe 1 2248.8 2317.2
- groupe_ages 3 2282.1 2335.3
- etudes 4 2380.5 2426.1
Step: AIC=2300.97
sport ~ sexe + groupe_ages + etudes
Df Deviance AIC
<none> 2232.6 2301.0
- sexe 1 2249.2 2310.0
- groupe_ages 3 2282.5 2328.1
- etudes 4 2385.2 2423.2
383
23.7 Afficher les indicateurs de performance
# A tibble: 1 x 8
null.deviance df.null logLik AIC BIC deviance df.residual nobs
<dbl> <int> <dbl> <dbl> <dbl> <dbl> <int> <int>
1 2617. 1999 -1114. 2257. 2341. 2227. 1985 2000
Name | Model | AIC (weights) | AICc (weights) | BIC (weights) | Tjur's R2 | RMSE | Sigma | L
-----------------------------------------------------------------------------------------------
mod | glm | 2257.1 (0.025) | 2257.3 (0.023) | 2341.1 (<.001) | 0.183 | 0.434 | 1.000 |
mod2 | glm | 2250.6 (0.651) | 2250.7 (0.654) | 2301.0 (0.971) | 0.181 | 0.435 | 1.000 |
mod4 | glm | 2252.0 (0.325) | 2252.1 (0.323) | 2308.0 (0.029) | 0.181 | 0.435 | 1.000 |
384
mod2 |>
tbl_regression(exponentiate = TRUE) |>
bold_labels() |>
add_glance_source_note()
385
Prenons un exemple, en ajoutant des valeurs manquantes à la
variable relig (pour cela nous allons recoder les refus et les ne
sait pas en NA).
d$relig_na <-
d$relig |>
fct_recode(
NULL = "Rejet",
NULL = "NSP ou NVPR"
)
step(mod_na)
Start: AIC=2096.64
sport ~ sexe + groupe_ages + etudes + relig_na + lecture.bd
Df Deviance AIC
- relig_na 3 2073.2 2093.2
- lecture.bd 1 2072.2 2096.2
<none> 2070.6 2096.6
- sexe 1 2088.6 2112.6
- groupe_ages 3 2118.0 2138.0
- etudes 4 2218.1 2236.1
Error in step(mod_na): le nombre de lignes utilisées a changé : supprimer les valeurs manquante
386
2. calculer notre modèle complet à partir de ce jeu de don-
nées ;
3. appliquer step() ;
4. recalculer le modèle réduit en repartant du jeu de données
complet.
Start: AIC=2096.64
sport ~ sexe + groupe_ages + etudes + relig_na + lecture.bd
Df Deviance AIC
- relig_na 3 2073.2 2093.2
- lecture.bd 1 2072.2 2096.2
<none> 2070.6 2096.6
- sexe 1 2088.6 2112.6
- groupe_ages 3 2118.0 2138.0
- etudes 4 2218.1 2236.1
387
Step: AIC=2093.19
sport ~ sexe + groupe_ages + etudes + lecture.bd
Df Deviance AIC
- lecture.bd 1 2074.6 2092.6
<none> 2073.2 2093.2
- sexe 1 2090.2 2108.2
- groupe_ages 3 2118.5 2132.5
- etudes 4 2221.4 2233.4
Step: AIC=2092.59
sport ~ sexe + groupe_ages + etudes
Df Deviance AIC
<none> 2074.6 2092.6
- sexe 1 2091.1 2107.1
- groupe_ages 3 2119.6 2131.6
- etudes 4 2227.2 2237.2
Cela s’exécute sans problème car tous les sous-modèles sont cal-
culés à partir de d_complet et donc ont bien le même nombre
d’observations. Cependant, dans notre modèle réduit, on a re-
tiré 137 observations en raison d’une valeur manquante sur la
variable relig_na, variable qui n’est plus présente dans notre
modèle réduit. Il serait donc pertinent de réintégrer ces obser-
vations.
Nous allons donc recalculer le modèle réduit mais à partir
de d. Inutile de recopier à la main la formule du mo-
dèle réduit, car nous pouvons l’obtenir directement avec
mod_na_reduit$formula.
388
nombre d’observations, ce qui change très légèrement les valeurs
des coefficients.
Ď Astuce
anova(mod_na_reduit2, mod_na_reduit_direct)
389
24 Prédictions marginales,
contrastes marginaux &
effets marginaux
Á Avertissement
390
Ĺ Note
24.1 Terminologie
391
Nous présenterons ces différents concepts plus en détail dans la
suite de ce chapitre.
Plusieurs packages proposent des fonctions pour le calcul
d’estimations marginales, {marginaleffects}, {emmeans},
{margins}, {effects}, ou encore {ggeffects}, chacun avec
des approches et un vocabulaire légèrement différent.
Le package {broom.helpers} fournit plusieurs tidiers qui
permettent d’appeler les fonctions de ces autres packages
et de renvoyer un tableau de données compatible avec
la fonction broom.helpers::tidy_plus_plus() et dès
lors de pouvoir générer un tableau mis en forme avec
gtsummary::tbl_regression() ou un graphique avec
ggstats::ggcoef_model().
library(tidyverse)
library(labelled)
library(gtsummary)
theme_gtsummary_language(
"fr",
decimal.mark = ",",
big.mark = " "
)
d <-
hdv2003 |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
392
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
heures.tv = "Heures de télévision / jour"
)
mod |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
393
Table 24.1: Odds Ratios du modèle logistique
[1] 1995
colnames(mf)
394
24.3 Prédictions marginales
Nos deux jeux de données sont donc identiques pour toutes les
autres variables et ne varient que pour le sexe. Nous pouvons
maintenant prédire, à partir de notre modèle ajusté, la proba-
bilité de faire du sport de chacun des individus de ces deux
nouveaux jeux de données, puis à en calculer la moyenne.
[1] 0.324814
[1] 0.4036624
395
library(marginaleffects)
mod |>
predictions(variables = "sexe", by = "sexe", type = "response")
mod |>
predictions(variables = "heures.tv", by = "heures.tv", type = "response")
396
Ĺ Note
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_marginal_predictions,
type = "response",
estimate_fun = scales::label_percent(accuracy = 0.1)
) |>
bold_labels() |>
modify_column_hide("p.value")
Prédictions
Caractéristique Marginales Moyennes 95% IC
Sexe
Femme 32.5% 29.9% –
35.0%
Homme 40.4% 37.5% –
43.2%
Groupe d’âges
25-44 ans 42.7% 39.3% –
46.2%
18-24 ans 51.2% 42.2% –
60.1%
397
Prédictions
Caractéristique Marginales Moyennes 95% IC
45-64 ans 29.9% 26.6% –
33.2%
65 ans et plus 24.9% 19.7% –
30.0%
Niveau d’études
Supérieur 53.2% 48.4% –
57.9%
Non documenté 59.2% 47.0% –
71.5%
Primaire 16.1% 11.9% –
20.4%
Technique / 34.0% 30.3% –
Professionnel 37.7%
Secondaire 31.8% 27.2% –
36.4%
Heures de
télévision / jour
0 41.0% 37.6% –
44.3%
1 38.6% 36.2% –
41.0%
2 36.3% 34.3% –
38.2%
3 34.0% 31.7% –
36.2%
12 16.8% 8.6% –
25.1%
La fonction broom.helpers::plot_marginal_predictions()
permet de visualiser les prédictions marginales à la moyenne en
réalisant une liste de graphiques, un par variable, que nous pou-
vons combiner avec patchwork::wrap_plots(). L’opérateur &
permet d’appliquer une fonction de {ggplot2} à chaque sous-
graphique. Ici, nous allons uniformiser l’axe des y.
398
patchwork::wrap_plots() &
scale_y_continuous(
limits = c(0, .8),
labels = scales::label_percent()
)
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Femme Homme 18−24 ans
25−44 ans
45−64 ans
65 ans et plus
Sexe Groupe d'âges
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté 0.0 2.5 5.0 7.5 10.0 12.5
Niveau d'études Heures de télévision / jour
p & coord_flip()
399
65 ans et plus
Groupe d'âges
Homme
45−64 ans
Sexe
25−44 ans
Femme
18−24 ans
10.0
Supérieur
7.5
Technique / Professionnel
5.0
Secondaire
2.5
Primaire
0.0
0% 20% 40% 60% 80% 0% 20% 40% 60% 80%
mod |>
ggstats::ggcoef_model(
tidy_fun = broom.helpers::tidy_marginal_predictions,
tidy_args = list(type = "response"),
show_p_values = FALSE,
signif_stars = FALSE,
significance = NULL,
vline = FALSE
) +
scale_x_continuous(labels = scales::label_percent())
400
Sexe Femme
Homme
[1] -0.910525
401
mod |> predict(type = "link", newdata = mf_hommes) |> mean()
[1] -0.4928844
mod |>
predictions(variables = "sexe", by = "sexe", type = "link")
[1] 0.2868924
mod |> predict(type = "link", newdata = mf_hommes) |> mean() |> logit_inverse()
[1] 0.3792143
mod |>
predictions(variables = "sexe", by = "sexe")
402
Homme 0.379 <0.001 31.9 0.344 0.416
403
0.273 0.378
Columns: rowid, rowidcf, estimate, p.value, s.value, conf.low, conf.high, sport, groupe_ages, e
Type: invlink(link)
Prédictions Marginales
Caractéristique à la Moyenne 95% IC
Sexe
Femme 23.9% 19.6% –
28.9%
Homme 32.3% 27.3% –
37.8%
404
Prédictions Marginales
Caractéristique à la Moyenne 95% IC
Groupe d’âges
25-44 ans 37.3% 32.1% –
42.8%
18-24 ans 46.8% 36.1% –
57.8%
45-64 ans 23.9% 19.6% –
28.9%
65 ans et plus 19.2% 14.0% –
25.6%
Niveau d’études
Supérieur 42.3% 36.0% –
48.9%
Non documenté 48.9% 34.7% –
63.2%
Primaire 10.1% 7.3% –
13.7%
Technique / 23.9% 19.6% –
Professionnel 28.9%
Secondaire 22.1% 17.7% –
27.2%
Heures de
télévision / jour
0 29.2% 23.6% –
35.5%
1 26.8% 21.9% –
32.3%
2 24.5% 20.1% –
29.5%
3 22.3% 18.1% –
27.2%
12 8.8% 4.6% –
16.4%
405
patchwork::wrap_plots() &
scale_y_continuous(
limits = c(0, .8),
labels = scales::label_percent()
) &
coord_flip()
65 ans et plus
Groupe d'âges
Homme
45−64 ans
Sexe
25−44 ans
Femme
18−24 ans
12.5
Non documenté
Niveau d'études
10.0
Supérieur
7.5
Technique / Professionnel
5.0
Secondaire
2.5
Primaire
0.0
0% 20% 40% 60% 80% 0% 20% 40% 60% 80%
mod |>
ggstats::ggcoef_model(
tidy_fun = broom.helpers::tidy_marginal_predictions,
tidy_args = list(newdata = "mean"),
show_p_values = FALSE,
signif_stars = FALSE,
significance = NULL,
vline = FALSE
406
) +
scale_x_continuous(labels = scales::label_percent())
Sexe Femme
Homme
sexe effect
sexe
Femme Homme
0.2868924 0.3792143
407
e$model.matrix
attr(,"contrasts")$groupe_ages
[1] "contr.treatment"
attr(,"contrasts")$etudes
[1] "contr.treatment"
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_all_effects,
408
estimate_fun = scales::label_percent(accuracy = 0.1)
) |>
bold_labels()
Prédictions Marginales
Caractéristique à la Moyenne 95% IC
Sexe
Femme 28.7% 25.8% –
31.8%
Homme 37.9% 34.4% –
41.6%
Groupe d’âges
18-24 ans 51.2% 41.0% –
61.3%
25-44 ans 41.5% 37.4% –
45.7%
45-64 ans 27.3% 23.9% –
30.9%
65 ans et plus 22.0% 17.4% –
27.5%
Niveau d’études
Primaire 14.9% 11.3% –
19.3%
Secondaire 30.7% 26.2% –
35.7%
Technique / 32.9% 29.1% –
Professionnel 37.0%
Supérieur 53.4% 48.3% –
58.4%
Non documenté 59.9% 46.6% –
71.8%
409
Prédictions Marginales
Caractéristique à la Moyenne 95% IC
Heures de
télévision / jour
0 38.9% 34.8% –
43.2%
3 30.7% 28.1% –
33.4%
6 23.6% 18.9% –
28.9%
9 17.7% 11.9% –
25.4%
10 16.0% 10.1% –
24.4%
mod |>
effects::allEffects() |>
plot()
410
sexe effect plot groupe_ages effect plot
0.6
sport
sport
0.40 0.5
0.35 0.4
0.3
0.30 0.2
Femme Homme 18−2425−44
ans 45−64
ans65 ans
ans et plus
sexe groupe_ages
0.7 0.40
sport
sport
0.6
0.5
0.4 0.35
0.30
0.25
0.3
0.2 0.20
0.15
0.10
Primaire
Technique
Secondaire
/ Professionnel
Supérieur
Non documenté 0 2 4 6 8 10
etudes heures.tv
411
Sexe Femme
Homme
24.3.3 Variantes
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_ggpredict,
estimate_fun = scales::label_percent(accuracy = 0.1)
) |>
bold_labels()
412
Table 24.5: Prédictions marginales avec ggpredict()
Prédictions
Caractéristique Marginales 95% IC
Sexe
Femme 23.8% 15.3% –
35.1%
Homme 32.2% 21.4% –
45.4%
Groupe d’âges
18-24 ans 23.8% 15.3% –
35.1%
25-44 ans 17.5% 12.7% –
23.5%
45-64 ans 10.1% 7.3% –
13.7%
65 ans et plus 7.8% 5.5% –
10.9%
Niveau d’études
Primaire 23.8% 15.3% –
35.1%
Secondaire 44.2% 33.0% –
56.1%
Technique / 46.8% 36.1% –
Professionnel 57.8%
Supérieur 67.2% 56.2% –
76.6%
Non documenté 72.8% 62.8% –
80.9%
Heures de télévision
/ jour
0 29.1% 18.7% –
42.3%
1 26.7% 17.2% –
38.9%
2 24.4% 15.7% –
35.8%
3 22.2% 14.2% –
33.0%
4 20.2% 12.8% –
30.4%
413
Prédictions
Caractéristique Marginales 95% IC
5 18.3% 11.4% –
28.2%
6 16.6% 10.0% –
26.1%
7 15.0% 8.8% –
24.3%
8 13.5% 7.7% –
22.7%
9 12.1% 6.6% –
21.2%
10 10.9% 5.7% –
19.9%
11 9.8% 4.9% –
18.7%
12 8.8% 4.2% –
17.6%
mod |>
ggeffects::ggpredict() |>
lapply(plot) |>
patchwork::wrap_plots()
414
Predicted probabilities of PratiquePredicted
un sport ?probabilities of Pratique un sport ?
Pratique un sport ?
Pratique un sport ?
40% 30%
30% 20%
20% 10%
Pratique un sport ?
80% 40%
60% 30%
40% 20%
10%
20%
Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté 0.0 2.5 5.0 7.5 10.0 12.5
Niveau d'études Heures de télévision / jour
415
Type: response
pred$estimate[2] - pred$estimate[1]
[1] 0.07884839
Columns: term, contrast, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high
Type: response
Ď Astuce
Les contrastes calculés ici ont été moyennés sur l’ensemble des
valeurs observées. On parle donc de contrastes marginaux
moyens (average marginal contrasts).
Par défaut, chaque modalité est contrastée avec la première
modalité prise comme référence (voir exemple ci-dessous avec
la variable groupe_ages.
Regardons maintenant une variable continue.
416
avg_comparisons(mod, variables = "heures.tv")
Columns: term, contrast, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high
Type: response
avg_comparisons(mod)
417
<0.001 18.8 -0.3720 -0.1541
<0.001 11.9 -0.0348 -0.0105
<0.001 14.0 0.0402 0.1175
Columns: term, contrast, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high
Type: response
Contrastes
Marginaux p-
Caractéristique Moyens 95% IC valeur
Sexe
Homme - Femme +7.9% +4.0% – <0,001
+11.7%
Groupe d’âges
418
Contrastes
Marginaux p-
Caractéristique Moyens 95% IC valeur
25-44 ans - 18-24 -8.4% -18.1% – 0,086
ans +1.2%
45-64 ans - 18-24 -21.3% -31.2% – <0,001
ans -11.3%
65 ans et plus - -26.3% -37.2% – <0,001
18-24 ans -15.4%
Niveau d’études
Non documenté - +43.1% +29.5% <0,001
Primaire – +56.6%
Secondaire - +15.7% +9.5% – <0,001
Primaire +21.8%
Supérieur - +37.0% +30.4% <0,001
Primaire – +43.6%
Technique / +17.8% +12.0% <0,001
Professionnel - – +23.6%
Primaire
Heures de
télévision / jour
+1 -2.3% -3.5% – <0,001
-1.1%
ggstats::ggcoef_model(
mod,
tidy_fun = broom.helpers::tidy_marginal_contrasts
) +
ggplot2::scale_x_continuous(
labels = scales::label_percent(style_positive = "plus")
)
419
Sexe Homme − Femme (p<0.001***)
Ď Astuce
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_marginal_contrasts,
variables_list = list(
list(heures.tv = 2),
list(groupe_ages = "pairwise"),
list(etudes = "sequential")
),
estimate_fun = scales::label_percent(
accuracy = 0.1,
style_positive = "plus"
)
) |>
bold_labels()
420
Table printed with `knitr::kable()`, not {gt}. Learn why at
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
Contrastes
Marginaux 95% p-
Caractéristique Moyens IC valeur
Heures de
télévision / jour
+2 -4.5% -7.0% – <0,001
-2.1%
Groupe d’âges
25-44 ans - 18-24 -8.4% -18.1% 0,086
ans – +1.2%
45-64 ans - 18-24 -21.3% -31.2% <0,001
ans – -11.3%
45-64 ans - 25-44 -12.8% -17.6% <0,001
ans – -8.1%
65 ans et plus - -26.3% -37.2% <0,001
18-24 ans – -15.4%
65 ans et plus - -17.9% -24.3% <0,001
25-44 ans – -11.4%
65 ans et plus - -5.0% -11.0% 0,10
45-64 ans – +0.9%
Niveau d’études
Non documenté - +6.1% -7.0% – 0,4
Supérieur +19.2%
Secondaire - +15.7% +9.5% – <0,001
Primaire +21.8%
Supérieur - +19.2% +13.3% <0,001
Technique / –
Professionnel +25.1%
Technique / +2.1% -3.8% – 0,5
Professionnel - +8.0%
Secondaire
421
On peut obtenir le même résultat avec
broom.helpers::tidy_avg_comparison() avec une
syntaxe un peu plus simple (en passant une liste
via variables au lieu d’une liste de listes via
variables_list).
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_avg_comparisons,
variables = list(
heures.tv = 2,
groupe_ages = "pairwise",
etudes = "sequential"
),
estimate_fun = scales::label_percent(
accuracy = 0.1,
style_positive = "plus"
)
) |>
bold_labels()
Contrastes
Marginaux 95% p-
Caractéristique Moyens IC valeur
Niveau d’études
Non documenté - +6.1% -7.0% – 0,4
Supérieur +19.2%
Secondaire - +15.7% +9.5% – <0,001
Primaire +21.8%
Supérieur - +19.2% +13.3% <0,001
Technique / –
Professionnel +25.1%
Technique / +2.1% -3.8% – 0,5
Professionnel - +8.0%
Secondaire
422
Groupe d’âges
25-44 ans - 18-24 -8.4% -18.1% 0,086
ans – +1.2%
45-64 ans - 18-24 -21.3% -31.2% <0,001
ans – -11.3%
45-64 ans - 25-44 -12.8% -17.6% <0,001
ans – -8.1%
65 ans et plus - -26.3% -37.2% <0,001
18-24 ans – -15.4%
65 ans et plus - -17.9% -24.3% <0,001
25-44 ans – -11.4%
65 ans et plus - -5.0% -11.0% 0,10
45-64 ans – +0.9%
Heures de
télévision / jour
+2 -4.5% -7.0% – <0,001
-2.1%
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_marginal_contrasts,
newdata = "mean",
estimate_fun = scales::label_percent(
423
accuracy = 0.1,
style_positive = "plus"
)
) |>
bold_labels()
Contrastes
Marginaux à la p-
Caractéristique Moyenne 95% IC valeur
Sexe
Homme - Femme +8.4% +4.3% – <0,001
+12.5%
Groupe d’âges
25-44 ans - 18-24 -9.5% -20.5% – 0,090
ans +1.5%
45-64 ans - 18-24 -22.9% -33.8% – <0,001
ans -11.9%
65 ans et plus - -27.6% -39.2% – <0,001
18-24 ans -16.1%
Niveau d’études
Non documenté - +38.8% +24.1% <0,001
Primaire –
+53.5%
Secondaire - +12.0% +7.0% – <0,001
Primaire +17.1%
Supérieur - +32.2% +25.7% <0,001
Primaire –
+38.7%
Technique / +13.9% +9.0% – <0,001
Professionnel - +18.7%
Primaire
Heures de
télévision / jour
424
Contrastes
Marginaux à la p-
Caractéristique Moyenne 95% IC valeur
+1 -2.2% -3.4% – <0,001
-1.0%
ggstats::ggcoef_model(
mod,
tidy_fun = broom.helpers::tidy_marginal_contrasts,
tidy_args = list(newdata = "mean")
) +
ggplot2::scale_x_continuous(
labels = scales::label_percent(style_positive = "plus")
)
425
24.5 Pentes marginales / Effets marginaux
avg_slopes(mod)
426
etudes Technique / Professionnel - Primaire 0.1781 0.0295 6.04
groupe_ages 25-44 ans - 18-24 ans -0.0844 0.0492 -1.71
groupe_ages 45-64 ans - 18-24 ans -0.2127 0.0507 -4.20
groupe_ages 65 ans et plus - 18-24 ans -0.2631 0.0556 -4.73
heures.tv dY/dX -0.0227 0.0062 -3.66
sexe Homme - Femme 0.0788 0.0197 4.00
Pr(>|z|) S 2.5 % 97.5 %
<0.001 31.0 0.2954 0.5665
<0.001 20.6 0.0952 0.2184
<0.001 90.8 0.3040 0.4361
<0.001 29.3 0.1203 0.2359
0.0865 3.5 -0.1808 0.0121
<0.001 15.2 -0.3121 -0.1133
<0.001 18.8 -0.3720 -0.1541
<0.001 11.9 -0.0348 -0.0105
<0.001 14.0 0.0402 0.1175
Columns: term, contrast, estimate, std.error, statistic, p.value, s.value, conf.low, conf.high
Type: response
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_avg_slopes,
estimate_fun = scales::label_percent(
accuracy = 0.1,
style_positive = "plus"
)
) |>
bold_labels()
427
Table 24.10: Effets marginaux moyens
Effets
Marginaux p-
Caractéristique Moyens 95% IC valeur
Niveau d’études
Non documenté - +43.1% +29.5% – <0,001
Primaire +56.6%
Secondaire - +15.7% +9.5% – <0,001
Primaire +21.8%
Supérieur - Primaire +37.0% +30.4% – <0,001
+43.6%
Technique / +17.8% +12.0% – <0,001
Professionnel - +23.6%
Primaire
Groupe d’âges
25-44 ans - 18-24 ans -8.4% -18.1% – 0,086
+1.2%
45-64 ans - 18-24 ans -21.3% -31.2% – <0,001
-11.3%
65 ans et plus - -26.3% -37.2% – <0,001
18-24 ans -15.4%
Heures de
télévision / jour
dY/dX -2.3% -3.5% – <0,001
-1.1%
Sexe
Homme - Femme +7.9% +4.0% – <0,001
+11.7%
ggstats::ggcoef_model(
mod,
tidy_fun = broom.helpers::tidy_avg_slopes
) +
ggplot2::scale_x_continuous(
labels = scales::label_percent(style_positive = "plus")
)
428
Niveau d'études Non documenté − Primaire (p<0.001***)
Secondaire − Primaire (p<0.001***)
Supérieur − Primaire (p<0.001***)
Technique / Professionnel − Primaire (p<0.001***)
# A tibble: 9 x 5
term estimate std.error statistic p.value
<chr> <dbl> <dbl> <dbl> <dbl>
1 etudesNon documenté 0.431 0.0691 6.23 4.60e-10
2 etudesSecondaire 0.157 0.0314 4.99 6.10e- 7
3 etudesSupérieur 0.370 0.0337 11.0 4.69e-28
4 etudesTechnique / Professionnel 0.178 0.0295 6.04 1.53e- 9
5 groupe_ages25-44 ans -0.0844 0.0492 -1.71 8.65e- 2
6 groupe_ages45-64 ans -0.213 0.0507 -4.20 2.73e- 5
7 groupe_ages65 ans et plus -0.263 0.0556 -4.73 2.21e- 6
8 heures.tv -0.0227 0.00620 -3.66 2.56e- 4
9 sexeHomme 0.0788 0.0197 4.00 6.26e- 5
429
mod |>
tbl_regression(
tidy_fun = broom.helpers::tidy_margins,
estimate_fun = scales::label_percent(
accuracy = 0.1,
style_positive = "plus"
)
) |>
bold_labels()
Effets
Marginaux p-
Caractéristique Moyens 95% IC valeur
Niveau d’études
Primaire — —
Non documenté +43.1% +29.5% – <0,001
+56.6%
Secondaire +15.7% +9.5% – <0,001
+21.8%
Supérieur +37.0% +30.4% – <0,001
+43.6%
Technique / +17.8% +12.0% – <0,001
Professionnel +23.6%
Groupe d’âges
18-24 ans — —
25-44 ans -8.4% -18.1% – 0,086
+1.2%
45-64 ans -21.3% -31.2% – <0,001
-11.3%
65 ans et plus -26.3% -37.2% – <0,001
-15.4%
Heures de -2.3% -3.5% – <0,001
télévision / jour -1.1%
430
Effets
Marginaux p-
Caractéristique Moyens 95% IC valeur
Sexe
Femme — —
Homme +7.9% +4.0% – <0,001
+11.7%
ggstats::ggcoef_model(
mod,
tidy_fun = broom.helpers::tidy_margins
) +
ggplot2::scale_x_continuous(
labels = scales::label_percent(style_positive = "plus")
)
Sexe Femme
Homme (p<0.001***)
−40%
−20%0%+20%
+40%
+60%
Average Marginal Effects
431
24.6 Lectures complémentaires (en anglais)
24.7 webin-R
432
25 Contrastes (variables
catégorielles)
433
Regardons la moyenne de marker pour chaque valeur de
grade.
library(tidyverse)
library(gtsummary)
trial |>
select(marker, grade) |>
tbl_summary(
by = grade,
statistic = marker ~ "{mean}",
digits = marker ~ 4
) |>
add_overall(last = TRUE)
Call:
lm(formula = marker ~ grade, data = trial)
Coefficients:
(Intercept) gradeII gradeIII
1.0669 -0.3864 -0.0711
434
Pour bien interpréter ces coefficients, il faut comprendre
comment la variable grade a été transformée avant d’être
inclue dans le modèle. Nous pouvons voir cela avec la fonction
contrasts().
contrasts(trial$grade)
II III
I 0 0
II 1 0
III 0 1
435
être fait avec gtsummary::tbl_regression() avec l’option
add_estimate_to_reference_rows = TRUE.
mod1_trt |>
tbl_regression(
intercept = TRUE,
add_estimate_to_reference_rows = TRUE
)
library(questionr)
data("hdv2003")
library(tidyverse)
436
right = FALSE,
include.lowest = TRUE
) |>
fct_recode(
"16-24" = "[16,25)",
"25-44" = "[25,45)",
"45-64" = "[45,65)",
"65+" = "[65,99]"
)
) |>
labelled::set_variable_labels(
groupe_ages = "Groupe d'âges",
sexe = "Sexe"
)
Coefficients:
(Intercept) sexeFemme groupe_ages25-44 groupe_ages45-64
0.9021 -0.4455 -0.6845 -1.6535
groupe_ages65+
-2.3198
437
Le modèle contient 5 termes : 1 intercept, 1 coefficient pour
la variable sexe et 3 coefficients pour la variable groupe_ages.
Comme précédemment, nous pouvons constater que les va-
riables à n modalités sont remplacées par défaut (contrastes
de type traitement) par n-1 variables binaires, la première
modalité jouant à chaque fois le rôle de modalité de référence.
contrasts(hdv2003$sexe)
Femme
Homme 0
Femme 1
contrasts(hdv2003$groupe_ages)
[1] 0.7113809
438
variables, soit pour les 16-24 ans ici) la correction à appliquer à
l’intercept pour obtenir la probabilité de faire du sport. Il s’agit
donc de la différence entre les femmes et les hommes pour le
groupe des 16-24 ans.
inv_logit(0.9021 - 0.4455)
[1] 0.6122073
library(ggeffects)
ggpredict(mod2_trt, "sexe") |> plot()
70%
sport
60%
Homme Femme
Sexe
439
mod2_trt |>
tbl_regression(
exponentiate = TRUE,
intercept = TRUE,
add_estimate_to_reference_rows = TRUE
) |>
bold_labels()
Or, 0,64 correspond bien à l’odds ratio entre 61% et 71% (que
l’on peut calculer avec questionr::odds.ratio()).
questionr::odds.ratio(0.6122, 0.7114)
[1] 0.6404246
440
Pour prédire la probabilité de faire du sport pour un profil
particulier, il faut prendre en compte toutes les termes qui
s’appliquent et qui s’ajoutent à l’intercept. Par exemple, pour
une femme de 50 ans il faut considérer l’intercept (0.9021), le
coefficient sexeFemme (-0.4455) et le coefficient groupe_ages45-
64 (-1.6535). Sa probabilité de faire du sport est donc de 23%.
[1] 0.2320271
contr.treatment(4, base = 2)
1 3 4
1 1 0 0
2 0 0 0
3 0 1 0
4 0 0 1
contr.SAS(4)
1 2 3
1 1 0 0
2 0 1 0
3 0 0 1
4 0 0 0
441
Les contrastes peuvent être modifiés de deux manières : au mo-
ment de la construction du modèle (via l’option contrasts) ou
comme attribut des variables (via la fonction contrasts()).
ggstats::ggcoef_compare(
list(mod2_trt, mod2_trt_bis),
exponentiate = TRUE,
type = "faceted"
442
)
1 2
Sexe
Homme
Femme
Groupe d'âges
16−24
25−44
45−64
65+
ggstats::ggcoef_compare(
list(mod2_trt, mod2_trt_bis),
tidy_fun = broom.helpers::tidy_marginal_predictions,
type = "dodge",
vline = FALSE
443
)
Sexe Femme
Homme
16−24
45−64
65+
1 2
444
mod1_sum
Call:
lm(formula = marker ~ grade, data = trial)
Coefficients:
(Intercept) grade1 grade2
0.9144 0.1525 -0.2339
[1] 0.9159895
moy_groupe <-
trial |>
dplyr::group_by(grade) |>
dplyr::summarise(moyenne_marker = mean(marker, na.rm = TRUE))
moy_groupe
# A tibble: 3 x 2
grade moyenne_marker
<fct> <dbl>
1 I 1.07
2 II 0.681
3 III 0.996
mean(moy_groupe$moyenne_marker)
445
[1] 0.9144384
contrasts(trial$grade)
[,1] [,2]
I 1 0
II 0 1
III -1 -1
mod1_sum |>
tbl_regression(
intercept = TRUE,
446
add_estimate_to_reference_rows = TRUE
) |>
bold_labels()
ggstats::ggcoef_model(mod1_sum)
Grade
I (p=0.078)
II (p=0.008**)
III (p=0.355)
447
de variance expliquée, la somme des résidus ou encore l’AIC
sont identiques. En un sens, il s’agit du même modèle. C’est
seulement la manière d’interpréter les coefficients du modèle
qui change.
448
Characteristic OR 95% CI p-value
(Intercept) 0.62 0.55, 0.69 <0.001
Sexe
Homme 1.25 1.13, 1.38 <0.001
Femme 0.80 0.72, 0.89 <0.001
Groupe d’âges
16-24 3.20 2.49, 4.15 <0.001
25-44 1.62 1.38, 1.89 <0.001
45-64 0.61 0.52, 0.72 <0.001
65+ 0.31 0.24, 0.42 <0.001
Sexe
Homme (p<0.001***)
Femme (p<0.001***)
Groupe d'âges
16−24 (p<0.001***)
25−44 (p<0.001***)
45−64 (p<0.001***)
65+ (p<0.001***)
449
anova(mod2_trt, mod2_sum, test = "Chisq")
ggstats::ggcoef_compare(
list(mod2_trt, mod2_sum),
tidy_fun = broom.helpers::tidy_marginal_predictions,
type = "dodge",
vline = FALSE
)
Sexe Femme
Homme
16−24
45−64
65+
1 2
450
dalité à la seconde, etc. Ils sont disponibles avec la fonction
MASS::contr.sdif().
Illustrons cela avec un exemple.
mean(moy_groupe$moyenne_marker)
[1] 0.9144384
Cela est lié au fait que la somme des coefficients dans ce type
de contrastes est égale à 0.
451
MASS::contr.sdif(3)
2-1 3-2
1 -0.6666667 -0.3333333
2 0.3333333 -0.3333333
3 0.3333333 0.6666667
[1] -0.3863997
moy_groupe$moyenne_marker[3] - moy_groupe$moyenne_marker[2]
[1] 0.3152964
452
sexe = MASS::contr.sdif,
groupe_ages = MASS::contr.sdif
)
)
mod2_sdif |>
tbl_regression(
exponentiate = TRUE,
intercept = TRUE
) |>
bold_labels()
453
Ď Astuce
mod2_trt |>
tbl_regression(
exponentiate = TRUE,
add_pairwise_contrasts = TRUE
) |>
bold_labels()
454
25.4 Autres types de contrastes
Call:
lm(formula = marker ~ stage, data = trial)
Coefficients:
(Intercept) stage1 stage2 stage3
0.91661 0.19956 0.03294 -0.02085
455
m <- trial |>
dplyr::group_by(stage) |>
dplyr::summarise(moy = mean(marker, na.rm = TRUE))
mean(m$moy)
[1] 0.9166073
m <- m |>
dplyr::mutate(
moy_cum = dplyr::cummean(moy),
moy_cum_prec = dplyr::lag(moy_cum),
ecart = moy_cum - moy_cum_prec
)
m
# A tibble: 4 x 5
stage moy moy_cum moy_cum_prec ecart
<fct> <dbl> <dbl> <dbl> <dbl>
1 T1 0.705 0.705 NA NA
2 T2 1.10 0.905 0.705 0.200
3 T3 1.00 0.937 0.905 0.0329
4 T4 0.854 0.917 0.937 -0.0208
456
Le premier terme stage1 compare la deuxième modalité (T2)
à la première (T1) et indique l’écart entre la moyenne des
moyennes de T1 et T2 et la moyenne de T1.
Le second terme stage2 compare la troisième modalité (T3) aux
deux premières (T1 et T2) et indique l’écart entre la moyenne
des moyennes de T1, T2 et T3 par rapport à la moyenne des
moyennes de T1 et T2.
Le troisième terme stage3 compare la quatrième modalité (T4)
aux trois premières (T1, T2 et T3) et indique l’écart entre la
moyenne des moyennes de T1, T2, T3 et T4 par rapport à la
moyenne des moyennes de T1, T2 et T3.
Les contrastes de Helmert sont ainsi un peu plus complexes à
interpréter et à réserver à des cas particuliers où ils prennent
tout leur sens.
.L .Q .C
T1 -0.6708204 0.5 -0.2236068
T2 -0.2236068 -0.5 0.6708204
T3 0.2236068 -0.5 -0.6708204
T4 0.6708204 0.5 0.2236068
457
Call:
lm(formula = marker ~ stage, data = trial)
Coefficients:
(Intercept) stage.L stage.Q stage.C
0.91661 0.07749 -0.27419 0.10092
458
26 Interactions
library(tidyverse)
library(labelled)
d <-
hdv2003 |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
),
etudes = nivetud |>
459
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
heures.tv = "Heures de télévision / jour"
)
460
mod |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
mod |>
broom.helpers::plot_marginal_predictions(type = "response") |>
461
patchwork::wrap_plots() &
scale_y_continuous(
limits = c(0, .8),
labels = scales::label_percent()
)
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Femme Homme 18−24 ans
25−44 ans
45−64 ans
65 ans et plus
Sexe Groupe d'âges
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté 0.0 2.5 5.0 7.5 10.0 12.5
Niveau d'études Heures de télévision / jour
462
mod2 |>
broom.helpers::plot_marginal_predictions(type = "response") |>
patchwork::wrap_plots(ncol = 1) &
scale_y_continuous(
labels = scales::label_percent()
)
60%
40%
20%
Primaire Secondaire
Technique / ProfessionnelSupérieur Non documenté
Niveau d'études
40%
30%
20%
10%
0.0 2.5 5.0 7.5 10.0 12.5
Heures de télévision / jour
70%
50%
30%
463
Ď Astuce
mod2 |>
broom.helpers::plot_marginal_predictions(
variables_list = "no_interaction",
type = "response"
) |>
patchwork::wrap_plots() &
scale_y_continuous(
labels = scales::label_percent()
)
60%
40% 50%
40%
35%
30%
30% 20%
Femme Homme 18−24 ans
25−44 ans
45−64 ans
65 ans et plus
Sexe Groupe d'âges
40%
60%
30%
40%
20%
20%
10%
Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté 0.0 2.5 5.0 7.5 10.0 12.5
Niveau d'études Heures de télévision / jour
464
nombre de coefficients (et donc de degrés de liberté). La ques-
tion se pose donc de savoir si l’ajout d’un terme d’interaction
améliore notre modèle.
En premier lieu, nous pouvons comparer les AIC des modèles
avec et sans interaction.
AIC(mod)
[1] 2230.404
AIC(mod2)
[1] 2223.382
L’AIC du modèle avec interaction est plus faible que celui sans
interaction, nous indiquant un gain : notre modèle avec inter-
action est donc meilleur.
On peut tester avec car::Anova() si l’interaction est statisti-
quement significative44 . 44
Lorsqu’il y a une interaction, il
est préférable d’utiliser le type III,
cf. Section 22.8. En toute rigueur,
car::Anova(mod2, type = "III")
il serait préférable de coder nos va-
riables catégorielles avec un contraste
de type somme (cf. Chapitre 25). En
Analysis of Deviance Table (Type III tests) pratique, nous pouvons nous en pas-
ser ici.
Response: sport
LR Chisq Df Pr(>Chisq)
sexe 19.349 1 1.089e-05 ***
groupe_ages 15.125 3 0.0017131 **
etudes 125.575 4 < 2.2e-16 ***
heures.tv 12.847 1 0.0003381 ***
sexe:groupe_ages 13.023 3 0.0045881 **
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
465
Nous pouvons également utiliser gtsummary::add_global_p().
mod2 |>
tbl_regression(exponentiate = TRUE) |>
add_global_p() |>
bold_labels()
466
ggtstats::ggcoef_model().
mod2 |>
ggstats::ggcoef_model(exponentiate = TRUE)
Sexe Femme
Homme (p<0.001***)
Secondaire (p<0.001***)
Supérieur (p<0.001***)
467
Supposons une femme de 60 ans, dont toutes les autres va-
riables correspondent aux modalités de référence (i.e. de ni-
veau primaire, qui ne regarde pas la télévision). Regardons ce
que prédit le modèle quant à sa probabilité de faire du sport
au travers d’une représentation graphique, grâce au package
{breakDown}.
library(breakDown)
logit <- function(x) exp(x)/(1+exp(x))
nouvelle_observation <- d[1, ]
nouvelle_observation$sexe[1] = "Femme"
nouvelle_observation$groupe_ages[1] = "45-64 ans"
nouvelle_observation$etud[1] = "Primaire"
nouvelle_observation$heures.tv[1] = 0
plot(
broken(mod2, nouvelle_observation, predict.function = betas),
trans = logit
) +
ylim(0, 1) +
ylab("Probabilité de faire du sport")
final_prognosis 0.021
heures.tv = 0 0
sexe = Femme 0
(Intercept) −0.298
468
En premier lieu, l’intercept s’applique et permet de déterminer
la probabilité de base de faire du sport à la référence. Femme
étant la modalité de référence pour la variable sexe, cela ne
modifie pas le calcul de la probabilité de faire du sport. Par
contre, il y a une modification induite par la modalité 45-64
ans de la variable groupe_ages.
Regardons maintenant la situation d’un homme de 20 ans.
nouvelle_observation$sexe[1] = "Homme"
nouvelle_observation$groupe_ages[1] = "18-24 ans"
plot(
broken(mod2, nouvelle_observation, predict.function = betas),
trans = logit
) +
ylim(0, 1.2) +
ylab("Probabilité de faire du sport")
final_prognosis 0.396
heures.tv = 0 0
(Intercept) −0.298
469
Regardons enfin la situation d’un homme de 60 ans.
final_prognosis 0.067
heures.tv = 0 0
(Intercept) −0.298
470
26.6 Définition alternative de l’interaction
ggstats::ggcoef_compare(
list("sexe * groupe_ages" = mod2, "sexe : groupe_ages" = mod3),
tidy_fun = broom.helpers::tidy_marginal_predictions,
significance = NULL,
471
vline = FALSE
) +
scale_x_continuous(labels = scales::label_percent())
Non documenté
Primaire
Technique / Professionnel
Secondaire
12
472
Par contre, regardons d’un peu plus près les coefficients de ce
nouveau modèle. Nous allons voir que leur interprétation est
légèrement différente.
mod3 |>
ggstats::ggcoef_model(exponentiate = TRUE)
Niveau d'études
Primaire
Secondaire (p<0.001***)
Supérieur (p<0.001***)
1 3 10
OR
473
plot(
broken(mod3, nouvelle_observation, predict.function = betas),
trans = logit
) +
ylim(0, 1.2) +
ylab("Probabilité de faire du sport")
final_prognosis 0.067
heures.tv = 0 0
(Intercept) −0.372
474
26.7 Identifier les interactions pertinentes
Start: AIC=2230.4
sport ~ sexe + groupe_ages + etudes + heures.tv
Df Deviance AIC
+ sexe:groupe_ages 3 2197.4 2223.4
+ sexe:etudes 4 2199.6 2227.6
+ sexe:heures.tv 1 2207.6 2229.6
<none> 2210.4 2230.4
+ groupe_ages:heures.tv 3 2207.0 2233.0
+ etudes:heures.tv 4 2207.4 2235.4
+ groupe_ages:etudes 11 2194.6 2236.6
- heures.tv 1 2224.0 2242.0
- sexe 1 2226.4 2244.4
- groupe_ages 3 2260.6 2274.6
- etudes 4 2334.3 2346.3
Step: AIC=2223.38
sport ~ sexe + groupe_ages + etudes + heures.tv + sexe:groupe_ages
Df Deviance AIC
475
+ sexe:heures.tv 1 2194.7 2222.7
<none> 2197.4 2223.4
+ groupe_ages:heures.tv 3 2193.5 2225.5
+ sexe:etudes 4 2192.1 2226.1
+ etudes:heures.tv 4 2194.6 2228.6
- sexe:groupe_ages 3 2210.4 2230.4
+ groupe_ages:etudes 11 2183.1 2231.1
- heures.tv 1 2210.2 2234.2
- etudes 4 2323.0 2341.0
Step: AIC=2222.67
sport ~ sexe + groupe_ages + etudes + heures.tv + sexe:groupe_ages +
sexe:heures.tv
Df Deviance AIC
<none> 2194.7 2222.7
- sexe:heures.tv 1 2197.4 2223.4
+ groupe_ages:heures.tv 3 2190.4 2224.4
+ sexe:etudes 4 2189.0 2225.0
+ etudes:heures.tv 4 2191.6 2227.6
- sexe:groupe_ages 3 2207.6 2229.6
+ groupe_ages:etudes 11 2180.7 2230.7
- etudes 4 2319.9 2339.9
mod4$formula
mod4 |>
broom.helpers::plot_marginal_predictions(type = "response") |>
patchwork::wrap_plots(ncol = 1) &
scale_y_continuous(
476
labels = scales::label_percent()
)
60%
40%
20%
Primaire Secondaire
Technique / ProfessionnelSupérieur Non documenté
Niveau d'études
70%
50%
30%
40%
30%
20%
10%
0%
0.0 2.5 5.0 7.5 10.0 12.5
Heures de télévision / jour
477
• Analysing interactions of fitted models par Helios De Ro-
sario Martínez
26.9 webin-R
478
27 Multicolinéarité
27.1 Définition
479
modèle linéaire et, par extension, un modèle linéaire généralisé
(dont les modèles de régression logistique).
Dans les faits, une multicolinéarité parfaite n’est quasiment
jamais observée. Mais une forte multicolinéarité entre plu-
sieurs variables peut poser problème dans l’estimation et
l’interprétation d’un modèle.
Une erreur fréquente est de confondre multicolinéarité et cor-
rélation. Si des variables colinéaires sont de facto fortement
corrélées entre elles, deux variables corrélées ne sont pas forcé-
ment colinéaires. En termes non statistiques, il y a colinéarité
lorsque deux ou plusieurs variables mesurent la même chose.
Prenons un exemple. Nous étudions les complications après
l’accouchement dans différentes maternités d’un pays en déve-
loppement. On souhaite mettre dans le modèle, à la fois le mi-
lieu de résidence (urbain ou rural) et le fait qu’il y ait ou non
un médecin dans la clinique. Or, dans la zone d’enquête, les
maternités rurales sont dirigées seulement par des sage-femmes
tandis que l’on trouve un médecin dans toutes les maternités
urbaines sauf une. Dès lors, dans ce contexte précis, le milieu de
résidence prédit presque totalement la présence d’un médecin et
on se retrouve face à une multicolinéarité (qui serait même par-
faite s’il n’y avait pas une clinique urbaine sans médecin). On
ne peut donc distinguer l’effet de la présence d’un médecin de
celui du milieu de résidence et il ne faut mettre qu’une seule de
ces deux variables dans le modèle, sachant que du point de vue
de l’interprétation elle capturera à la fois l’effet de la présence
d’un médecin et celui du milieu de résidence.
Par contre, si dans notre région d’étude, seule la moitié des
maternités urbaines disposait d’un médecin, alors le milieu de
résidence n’aurait pas été suffisant pour prédire la présence d’un
médecin. Certes, les deux variables seraient corrélées mais pas
colinéaires. Un autre exemple de corrélation sans colinéarité,
c’est la relation entre milieu de résidence et niveau d’instruction.
Il y a une corrélation entre ces deux variables, les personnes
résidant en ville étant généralement plus instruites. Cependant,
il existe également des personnes non instruites en ville et des
personnes instruites en milieu rural. Le milieu de résidence n’est
donc pas suffisant pour prédire le niveau d’instruction.
480
27.2 Mesure de la colinéarité
library(tidyverse)
library(labelled)
d <-
hdv2003 |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
481
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
heures.tv = "Heures de télévision / jour"
)
482
GVIF Df GVIF^(1/(2*Df))
sexe 1.024640 1 1.012245
groupe_ages 1.745492 3 1.097285
etudes 1.811370 4 1.077087
heures.tv 1.057819 1 1.028503
library(gtsummary)
theme_gtsummary_language(
"fr",
decimal.mark = ",",
big.mark = " "
)
mod |>
tbl_regression(exponentiate = TRUE) |>
bold_labels() |>
add_vif()
95% p- Adjusted
Caractéristique OR IC valeur GVIF GVIF
Sexe 1,0 1,0
Femme — —
Homme 1,52 1,24 – <0,001
1,87
Groupe d’âges 1,7 1,1
18-24 ans — —
483
95% p- Adjusted
Caractéristique OR IC valeur GVIF GVIF
25-44 ans 0,68 0,43 – 0,084
1,06
45-64 ans 0,36 0,23 – <0,001
0,57
65 ans et plus 0,27 0,16 – <0,001
0,46
Niveau 1,8 1,1
d’études
Primaire — —
Secondaire 2,54 1,73 – <0,001
3,75
Technique / 2,81 1,95 – <0,001
Professionnel 4,10
Supérieur 6,55 4,50 – <0,001
9,66
Non documenté 8,54 4,51 – <0,001
16,5
Heures de 0,89 0,83 – <0,001 1,1 1,0
télévision / 0,95
jour
Low Correlation
484
Les variables avec un FIV entre 5 et 10 sont présentées comme
ayant une corrélation moyenne et celles avec un FIV de 10 ou
plus une corrélation forte. Prenons un autre exemple.
mc
Low Correlation
Moderate Correlation
High Correlation
plot(mc)
485
Variable `Component` is not in your data frame :/
Collinearity
High collinearity (VIF) may inflate parameter uncertainty
Variance Inflation Factor (VIF, log−scaled)
30
10
1
am cyl gear vs vs:cyl wt
Low (< 5) Moderate (< 10) High (= 10)
mc |> performance::print_md()
486
27.3 La multicolinéarité est-elle toujours un
problème ?
487
Si vous spécifiez un modèle de régression avec x et x2 , il y a de
bonnes chances que ces deux variables soient fortement corré-
lées. De même, si votre modèle a x, z et xz, x et z sont suscep-
tibles d’être fortement corrélés avec leur produit. Il n’y a pas
de quoi s’inquiéter, car la valeur p de xz n’est pas affectée par
la multicolinéarité. Ceci est facile à démontrer : vous pouvez ré-
duire considérablement les corrélations en centrant les variables
(c’est-à-dire en soustrayant leurs moyennes) avant de créer les
puissances ou les produits. Mais la valeur p pour x2 ou pour xz
sera exactement la même, que l’on centre ou non. Et tous les
résultats pour les autres variables (y compris le R2 mais sans
les termes d’ordre inférieur) seront les mêmes dans les deux cas.
La multicolinéarité n’a donc pas de conséquences négatives.
3. Les variables avec des FIV élevés sont des variables
indicatrices (factices) qui représentent une variable ca-
tégorielle avec trois catégories ou plus.
Si la proportion de cas dans la catégorie de référence est faible,
les variables indicatrices auront nécessairement des FIV élevés,
même si la variable catégorielle n’est pas associée à d’autres
variables dans le modèle de régression.
Supposons, par exemple, qu’une variable de l’état matrimonial
comporte trois catégories : actuellement marié, jamais marié
et anciennement marié. Vous choisissez anciennement marié
comme catégorie de référence, avec des variables d’indicateur
pour les deux autres. Ce qui se passe, c’est que la corrélation
entre ces deux indicateurs devient plus négative à mesure que
la fraction de personnes dans la catégorie de référence diminue.
Par exemple, si 45 % des personnes ne sont jamais mariées, 45 %
sont mariées et 10 % sont anciennement mariées, les valeurs du
FIV pour les personnes mariées et les personnes jamais mariées
seront d’au moins 3,0.
Est-ce un problème ? Eh bien, cela signifie que les valeurs p
des variables indicatrices peuvent être élevées. Mais le test glo-
bal selon lequel tous les indicateurs ont des coefficients de zéro
n’est pas affecté par des FIV élevés. Et rien d’autre dans la
régression n’est affecté. Si vous voulez vraiment éviter des FIV
élevés, il suffit de choisir une catégorie de référence avec une
plus grande fraction des cas. Cela peut être souhaitable pour
éviter les situations où aucun des indicateurs individuels n’est
488
statistiquement significatif, même si l’ensemble des indicateurs
est significatif.
27.4 webin-R
489
partie IV
490
28 Définir un plan
d’échantillonnage
491
tillons possibles (de même taille) ont la même probabilité d’être
choisis et tous les éléments de la population ont une chance
égale de faire partie de l’échantillon. C’est l’échantillonnage le
plus simple : chaque individu à la même probabilité d’être sé-
lectionné.
L’échantillonnage stratifié est une méthode qui consiste
d’abord à subdiviser la population en groupes homogènes
(strates) pour ensuite extraire un échantillon aléatoire de
chaque strate. Cette méthode suppose une connaissance de la
structure de la population. Pour estimer les paramètres, les
résultats doivent être pondérés par l’importance relative de
chaque strate dans la population.
L’échantillonnage par grappes est une méthode qui consiste à
choisir un échantillon aléatoire d’unités qui sont elles-mêmes
des sous-ensembles de la population (grappes ou clusters en an-
glais). Cette méthode suppose que les unités de chaque grappe
sont représentatives. Elle possède l’avantage d’être souvent plus
économique.
Il est possible de combiner plusieurs de ces approches. Par
exemple, les Enquêtes Démographiques et de Santé 48 (EDS) 48
Vaste programme d’enquêtes réa-
sont des enquêtes stratifiées en grappes à deux degrés. Dans un lisées à intervalles réguliers dans les
pays à faible et moyen revenu, dispo-
premier temps, la population est divisée en strates par région et
nibles sur https://dhsprogram.com/.
milieu de résidence. Dans chaque strate, des zones d’enquêtes,
correspondant à des unités de recensement, sont tirées au sort
avec une probabilité proportionnelle au nombre de ménages de
chaque zone au dernier recensement de population. Enfin, au
sein de chaque zone d’enquête sélectionnée, un recensement de
l’ensemble des ménages est effectué puis un nombre identique
de ménages par zone d’enquête est tiré au sort de manière aléa-
toire simple.
492
L'argument data permet de spécifier le tableau de données
contenant les observations.
L’argument ids est obligatoire et spécifie sous la forme d’une
formule les identifiants des différents niveaux d’un tirage en
grappe. S’il s’agit d’un échantillon aléatoire simple, on entrera
ids = ~ 1. Autre situation : supposons une étude portant sur
la population française. Dans un premier temps, on a tiré au
sort un certain nombre de départements français. Dans un se-
cond temps, on tire au sort dans chaque département des com-
munes. Dans chaque commune sélectionnée, on tire au sort
des quartiers. Enfin, on interroge de manière exhaustive toutes
les personnes habitant les quartiers enquêtés. Notre fichier de
données devra donc comporter pour chaque observation les va-
riables id_departement, id_commune et id_quartier. On écrira
alors pour l’argument ids la valeur suivante :
ids = ~ id_departement + id_commune + id_quartier.
Si l’échantillon est stratifié, on spécifiera les strates à
l’aide de l’argument strata en spécifiant la variable conte-
nant l’identifiant des strates. Par exemple : strata = ~
id_strate.
Il faut encore spécifier les probabilités de tirage de chaque clus-
ter /grappe ou bien la pondération des individus. Si l’on dis-
pose de la probabilité de chaque observation d’être sélection-
née, on utilisera l’argument probs. Si, par contre, on connaît
la pondération de chaque observation (qui doit être proportion-
nelle à l’inverse de cette probabilité), on utilisera l’argument
weights.
Si l’échantillon est stratifié, qu’au sein de chaque strate les in-
dividus ont été tirés au sort de manière aléatoire et que l’on
connaît la taille de chaque strate, il est possible de ne pas avoir
à spécifier la probabilité de tirage ou la pondération de chaque
observation. Il est préférable de fournir une variable contenant
la taille de chaque strate à l’argument fpc. De plus, dans ce cas-
là, une petite correction sera appliquée au modèle pour prendre
en compte la taille finie de chaque strate.
On peut tout à fait définir un échantillonnage aléatoire
simple (on considère donc que toutes les observations ont
493
le même poids, égal à 1). Pour rappel, en l’absence de clus-
ters/grappes, il faut préciser ids = ~ 1, ce paramètre n’ayant
pas de valeur par défaut.
p_iris
494
Independent Sampling design (with replacement)
survey::svydesign(ids = ~1, data = titanic, weights = ~n)
495
la taille des grappes est connue et renseignée dans les variables
fpc1 et fpc2 que nous pourrons donc transmettre via l’argument
fpc.
496
strata = ~ V022,
weights = ~ poids
)
class(t_iris)
497
[1] "tbl_svy" "survey.design2" "survey.design"
498
Pour une enquête en grappes à 1 degré, pour laquelle
l’identifiant des grappes (clusters) est indiqué par la variable
dnum.
499
Called via srvyr
Sampling variables:
- ids: `dnum + snum`
- fpc: `fpc1 + fpc2`
Data variables: cds (chr), stype (fct), name (chr), sname (chr), snum (dbl),
dname (chr), dnum (int), cname (chr), cnum (int), flag (int), pcttest (int),
api00 (int), api99 (int), target (int), growth (int), sch.wide (fct),
comp.imp (fct), both (fct), awards (fct), meals (int), ell (int), yr.rnd
(fct), mobility (int), acs.k3 (int), acs.46 (int), acs.core (int), pct.resp
(int), not.hsg (int), hsg (int), some.col (int), col.grad (int), grad.sch
(int), avg.ed (dbl), full (int), emer (int), enroll (int), api.stu (int), pw
(dbl), fpc1 (dbl), fpc2 (int[1d])
500
28.4 webin-R
501
29 Manipulation de données
pondérées
Rows: 32
Columns: 5
$ Class <chr> "1st", "2nd", "3rd", "Crew", "1st", "2nd", "3rd", "Crew", "1s~
$ Sex <chr> "Male", "Male", "Male", "Male", "Female", "Female", "Female",~
$ Age <chr> "Child", "Child", "Child", "Child", "Child", "Child", "Child"~
$ Survived <chr> "No", "No", "No", "No", "No", "No", "No", "No", "No", "No", "~
$ n <dbl> 0, 0, 35, 0, 0, 0, 17, 0, 118, 154, 387, 670, 4, 13, 89, 3, 5~
502
29.1 Utilisation de {srvyr}
library(srvyr)
filter
503
Á Avertissement
t_titanic |>
group_by(Sex, Class, Survived) |>
summarise(taux_survie = survey_prop()) |>
filter(Survived == "Yes")
# A tibble: 8 x 5
# Groups: Sex, Class [8]
504
Sex Class Survived taux_survie taux_survie_se
<chr> <chr> <chr> <dbl> <dbl>
1 Female 1st Yes 0.972 0.0384
2 Female 2nd Yes 0.877 0.145
3 Female 3rd Yes 0.459 0.306
4 Female Crew Yes 0.870 0.163
5 Male 1st Yes 0.344 0.312
6 Male 2nd Yes 0.140 0.150
7 Male 3rd Yes 0.173 0.183
8 Male Crew Yes 0.223 0.249
505
pos variable label col_type missing values
4 Survived A survécu au naufrage ? chr 0
506
30 Analyses uni- et bivariées
pondérées
507
filter
library(gtsummary)
#Uighur
theme_gtsummary_language(
language = "fr",
decimal.mark = ",",
big.mark = ""
)
508
arrière plan, gtsummary::tbl_svysummary() appellera les
différentes fonctions statistiques de {survey} : la pondération
ainsi que les spécificités du plan d’échantillonnage seront donc
correctement prises en compte.
dp |>
tbl_svysummary(
by = milieu,
include = c(age, educ, travail)
) |>
add_overall(last = TRUE) |>
bold_labels()
urbain, Total,
N= rural, N N=
Caractéristique 1026 = 1002 2027
Âge révolu (en années) 26 (20 – 28 (22 – 27 (21 –
à la date de passation 33) 36) 35)
du questionnaire
Niveau d’éducation
aucun 414 681 1095
(40%) (68%) (54%)
primaire 251 257 507
(24%) (26%) (25%)
secondaire 303 61 364
(30%) (6,1%) (18%)
509
urbain, Total,
N= rural, N N=
Caractéristique 1026 = 1002 2027
supérieur 58 3 (0,3%) 61
(5,7%) (3,0%)
A un emploi ?
non 401 269 670
(39%) (27%) (33%)
oui 621 731 1351
(61%) (73%) (67%)
Manquant 5 1 6
ĺ Important
510
nipulations. Pour les cellules, on précisera le type
d’effectifs à afficher avec l’argument statistic. Pour
personnaliser l’affiche du nombre de valeurs man-
quantes, cela doit se faire à un niveau plus global via
gtsummary::set_gtsummary_theme(). Enfin, on passera
par gtsummary::modify_header() pour personnaliser
les en-têtes de colonne.
set_gtsummary_theme(
list("tbl_summary-str:missing_stat" = "{N_miss_unweighted} obs.")
)
dp |>
tbl_svysummary(
by = milieu,
include = c(educ, travail),
statistic = all_categorical() ~ "{p}% ({n_unweighted} obs.)",
digits = all_categorical() ~ c(1, 0)
) |>
modify_header(
all_stat_cols() ~ "**{level}** ({n_unweighted} obs.)"
) |>
bold_labels()
urbain (912
Caractéristique obs.) rural (1088 obs.)
Niveau
d’éducation
511
aucun 40,3% (375 obs.) 68,0% (763 obs.)
primaire 24,4% (213 obs.) 25,6% (247 obs.)
secondaire 29,5% (275 obs.) 6,1% (73 obs.)
supérieur 5,7% (49 obs.) 0,3% (5 obs.)
A un emploi ?
non 39,2% (370 obs.) 26,9% (296 obs.)
oui 60,8% (537 obs.) 73,1% (790 obs.)
Manquant 5 obs. 2 obs.
512
survey::svymean(~ age, dp)
mean SE
age 28.468 0.2697
2.5 % 97.5 %
age 27.93931 28.99653
$age
quantile ci.2.5 ci.97.5 se
0.25 21 21 22 0.2549523
0.5 27 27 28 0.2549523
0.75 35 35 37 0.5099045
attr(,"hasci")
[1] TRUE
attr(,"class")
[1] "newsvyquantile"
region
Nord Est Sud Ouest
611.0924 175.7404 329.2220 911.2197
513
survey::svytable(~milieu + educ, dp)
educ
milieu aucun primaire secondaire supérieur
urbain 413.608780 250.665214 303.058978 58.412688
rural 681.131096 256.694363 61.023980 2.679392
n % val%
Nord 611.1 30.1 30.1
Est 175.7 8.7 8.7
Sud 329.2 16.2 16.2
Ouest 911.2 44.9 44.9
Total 2027.3 100.0 100.0
educ
milieu aucun primaire secondaire supérieur Ensemble
urbain 37.8 49.4 83.2 95.6 50.6
rural 62.2 50.6 16.8 4.4 49.4
Total 100.0 100.0 100.0 100.0 100.0
514
survey::svyby(~age, ~region, dp, survey::svymean)
region age se
Nord Nord 29.03299 0.4753268
Est Est 27.54455 0.5261669
Sud Sud 28.96830 0.6148223
Ouest Ouest 28.08626 0.4458201
dp |>
tbl_svysummary(
include = c(age, region),
statistic = all_continuous() ~ "{mean} ({sd})"
) |>
add_ci() |>
bold_labels()
515
Table 30.3: Intervalles de confiance avec prise en compte du
plan d’échantillonnage
N= 95%
Caractéristique 2027 CI
Âge révolu (en années) à la date de 28 (9) 28, 29
passation du questionnaire
Région de résidence
Nord 611 28%,
(30%) 33%
Est 176 7,7%,
(8,7%) 9,8%
Sud 329 14%,
(16%) 18%
Ouest 911 42%,
(45%) 48%
dp |>
tbl_svysummary(
include = c(age, region),
by = milieu
) |>
add_p() |>
bold_labels()
516
https://www.danieldsjoberg.com/gtsummary/articles/rmarkdown.html
To suppress this message, include `message = FALSE` in code chunk header.
urbain, rural, N p-
Caractéristique N = 1026 = 1002 valeur
Âge révolu (en années) à 26 (20 – 28 (22 – <0,001
la date de passation du 33) 36)
questionnaire
Région de résidence <0,001
Nord 265 346
(26%) (35%)
Est 48 (4,7%) 128
(13%)
Sud 79 (7,7%) 250
(25%)
Ouest 633 278
(62%) (28%)
dp |>
group_by(region) |>
summarise(moy = survey_mean())
517
# A tibble: 4 x 3
region moy moy_se
<fct> <dbl> <dbl>
1 Nord 0.301 0.0127
2 Est 0.0867 0.00544
3 Sud 0.162 0.0102
4 Ouest 0.449 0.0147
dp |>
group_by(region) |>
summarise(moy = survey_mean(vartype = "ci"))
# A tibble: 4 x 4
region moy moy_low moy_upp
<fct> <dbl> <dbl> <dbl>
1 Nord 0.301 0.277 0.326
2 Est 0.0867 0.0760 0.0974
3 Sud 0.162 0.142 0.182
4 Ouest 0.449 0.421 0.478
dp |>
group_by(educ) |>
summarise(prop = survey_prop())
# A tibble: 4 x 3
educ prop prop_se
<fct> <dbl> <dbl>
518
1 aucun 0.540 0.0144
2 primaire 0.250 0.0127
3 secondaire 0.180 0.0110
4 supérieur 0.0301 0.00487
# A tibble: 8 x 5
# Groups: milieu [2]
milieu educ prop prop_low prop_upp
<fct> <fct> <dbl> <dbl> <dbl>
1 urbain aucun 0.403 0.364 0.444
2 urbain primaire 0.244 0.210 0.282
3 urbain secondaire 0.295 0.260 0.334
4 urbain supérieur 0.0569 0.0410 0.0785
5 rural aucun 0.680 0.643 0.715
6 rural primaire 0.256 0.223 0.292
7 rural secondaire 0.0609 0.0454 0.0813
8 rural supérieur 0.00268 0.00108 0.00660
dp |>
group_by(interact(milieu, educ)) |>
summarise(prop = survey_prop(vartype = "ci", proportion = TRUE))
519
# A tibble: 8 x 5
milieu educ prop prop_low prop_upp
<fct> <fct> <dbl> <dbl> <dbl>
1 urbain aucun 0.204 0.182 0.228
2 urbain primaire 0.124 0.105 0.145
3 urbain secondaire 0.149 0.130 0.171
4 urbain supérieur 0.0288 0.0207 0.0400
5 rural aucun 0.336 0.310 0.363
6 rural primaire 0.127 0.109 0.146
7 rural secondaire 0.0301 0.0224 0.0404
8 rural supérieur 0.00132 0.000535 0.00326
[1] 200
summary(apistrat$pw)
520
sum(apistrat$pw)
[1] 6194
yr.rnd
awards No Yes
No 2068.34 168.09
Yes 3274.06 683.51
data: tbl
X-squared = 113.84, df = 1, p-value < 2.2e-16
521
survey::svychisq(~ awards + yr.rnd, design = d_ponderation_simple)
data: NextMethod()
F = 2.9162, ndf = 1, ddf = 199, p-value = 0.08926
Le résultat est ici tout autre et notre test n’est plus significatif
au seuil de 5% ! Ici, les corrections de Rao & Scott permettent
justement de tenir compte que nous avons un échantillon de
seulement 200 observations.
Regardons maintenant si, à poids égal, il y a une différence
entre une enquête stratifiée et une enquête en grappes.
# Pondération simple
survey::svytable(~ awards + yr.rnd, design = d_ponderation_simple)
yr.rnd
awards No Yes
No 2068.34 168.09
Yes 3274.06 683.51
data: NextMethod()
F = 2.9162, ndf = 1, ddf = 199, p-value = 0.08926
# Enquête stratifiée
d_strates <- apistrat |>
as_survey_design(weights = pw, strata = stype)
survey::svytable(~ awards + yr.rnd, design = d_strates)
522
yr.rnd
awards No Yes
No 2068.34 168.09
Yes 3274.06 683.51
data: NextMethod()
F = 2.9007, ndf = 1, ddf = 197, p-value = 0.09012
# Enquête en grappes
d_grappes <- apistrat |>
as_survey_design(weights = pw, ids = dnum)
survey::svytable(~ awards + yr.rnd, design = d_grappes)
yr.rnd
awards No Yes
No 2068.34 168.09
Yes 3274.06 683.51
data: NextMethod()
F = 3.1393, ndf = 1, ddf = 134, p-value = 0.0787
523
il faut appliquer des corrections en fonction du plan
d’échantillonnage !
Pas d’inquiétude, {survey} s’en occupe pour vous, dès lors que
le plan d’échantillonnage a correctement été défini.
524
31 Graphiques pondérés
Á Avertissement
525
v purrr 1.0.1
-- Conflicts ------------------------------------------ tidyverse_conflicts() --
x dplyr::filter() masks stats::filter()
x dplyr::lag() masks stats::lag()
i Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become
d <- labelled::unlabelled(femmes)
ggplot(d) +
aes(x = region, fill = test, weight = poids) +
geom_bar(position = "fill")
1.00
0.75
test
count
non
0.50
oui
manquant
0.25
0.00
Nord Est Sud Ouest
region
library(srvyr)
526
Attachement du package : 'srvyr'
filter
ggplot(dp$variables) +
aes(x = region, fill = test, weight = weights(dp)) +
geom_bar(position = "fill")
1.00
0.75
test
count
non
0.50
oui
manquant
0.25
0.00
Nord Est Sud Ouest
region
527
Ainsi, le code de notre graphique précédent s’écrit tout simple-
ment52 : 52
Notez que les poids ont déjà été
associés à la bonne esthétique et qu’il
n’est donc pas nécessaire de le refaire
ggstats::ggsurvey(dp) +
dans l’appel à aes().
aes(x = region, fill = test) +
geom_bar(position = "fill")
1.00
0.75
test
count
non
0.50
oui
manquant
0.25
0.00
Nord Est Sud Ouest
region
528
32 Régression logistique
binaire pondérée
library(tidyverse)
library(labelled)
data(hdv2003, package = "questionr")
d <-
hdv2003 |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
529
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
relig = "Rapport à la religion",
heures.tv = "Heures de télévision / jour",
poids = "Pondération de l'enquête"
)
library(srvyr)
library(survey)
dp <- d |>
as_survey_design(weights = poids)
530
La plupart du temps, les poids de pondération ne sont pas des
nombres entiers, mais des nombres décimaux. Or, la famille de
modèles binomiaux repose sur des nombres entiers de succès
et d’échecs. Avec une version récente53 de R, cela n’est pas 53
Si vous utilisez une version an-
problématique. Nous aurons simplement un avertissement. cienne de R, cela n’était tout simple-
ment pas possible. Vous obteniez un
message d’erreur et le modèle n’était
mod_binomial <- svyglm( pas calculé. Si c’est votre cas, op-
sport ~ sexe + groupe_ages + etudes + relig + heures.tv,
tez pour un modèle quasi-binomial ou
family = binomial, bien mettez à jour R.
design = dp
)
Simple, non ?
531
mod_quasi2 <- step(mod_quasi)
Start: AIC=2309.89
sport ~ sexe + groupe_ages + etudes + relig + heures.tv
Df Deviance AIC
- relig 5 2266.3 2302.2
<none> 2263.9 2309.9
- heures.tv 1 2276.2 2320.2
- sexe 1 2276.4 2320.4
- groupe_ages 3 2313.9 2353.8
- etudes 4 2383.5 2421.2
Step: AIC=2296.28
sport ~ sexe + groupe_ages + etudes + heures.tv
Df Deviance AIC
<none> 2266.3 2296.3
- heures.tv 1 2278.4 2306.4
- sexe 1 2279.0 2307.0
- groupe_ages 3 2318.3 2342.1
- etudes 4 2387.2 2408.8
532
step_with_na_survey <- function(model, design, ...) {
# list of variables
variables <- broom.helpers::model_list_variables(
model,
only_variable = TRUE
)
# design with no na
design_no_na <- design |>
srvyr::drop_na(dplyr::any_of(variables))
# refit the model without NAs
model_no_na <- update(model, data = design_no_na)
# apply step()
model_simplified <- step(model_no_na, ...)
# recompute simplified model using full data
update(model, formula = terms(model_simplified))
}
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",", big.mark = " ")
mod_quasi2 |>
tbl_regression(exponentiate = TRUE) |>
add_global_p(keep = TRUE) |>
add_vif() |>
bold_labels()
533
Warning in printHypothesis(L, rhs, names(b)): one or more coefficients in the hypothesis includ
arithmetic operators in their names;
the printed representation of the hypothesis will be omitted
Warning in printHypothesis(L, rhs, names(b)): one or more coefficients in the hypothesis includ
arithmetic operators in their names;
the printed representation of the hypothesis will be omitted
95% p- Adjusted
Caractéristique OR IC valeur GVIF GVIF
Sexe 0,005 1,0 1,0
Femme — —
Homme 1,44 1,12 – 0,005
1,87
Groupe d’âges <0,001 2,1 1,1
18-24 ans — —
25-44 ans 0,85 0,48 – 0,6
1,51
45-64 ans 0,40 0,22 – 0,003
0,73
65 ans et plus 0,37 0,19 – 0,004
0,72
Niveau <0,001 2,2 1,1
d’études
Primaire — —
Secondaire 2,66 1,62 – <0,001
4,38
Technique / 3,09 1,90 – <0,001
Professionnel 5,00
Supérieur 6,54 3,99 – <0,001
10,7
534
95% p- Adjusted
Caractéristique OR IC valeur GVIF GVIF
Non documenté 10,3 4,60 – <0,001
23,0
Heures de 0,89 0,82 – 0,006 1,1 1,0
télévision / 0,97
jour
mod_quasi2 |>
ggstats::ggcoef_model(exponentiate = TRUE)
Sexe Femme
Homme (p=0.005**)
535
mod_quasi2 |>
broom.helpers::plot_marginal_predictions(type = "response") |>
patchwork::wrap_plots() &
scale_y_continuous(
limits = c(0, .8),
labels = scales::label_percent()
)
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Femme Homme 18−24 ans
25−44 ans
45−64 ans
65 ans et plus
Sexe Groupe d'âges
80% 80%
60% 60%
40% 40%
20% 20%
0% 0%
Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté 0.0 2.5 5.0 7.5 10.0 12.5
Niveau d'études Heures de télévision / jour
536
partie V
Manipulation avancée
537
33 Fusion de tables
library(tidyverse)
library(nycflights13)
data(flights)
data(airports)
data(airlines)
538
que la table flights contient le code de la compagnie aérienne
du vol dans la variable carrier :
539
table seront associées à une autre en se basant non pas sur leur
position, mais sur les valeurs d’une ou plusieurs colonnes. Ces
colonnes sont appelées des clés.
Pour faire une jointure de ce type, on va utiliser la fonction
dplyr::left_join() :
fusion |>
select(month, day, carrier, name) |>
head(10)
# A tibble: 10 x 4
month day carrier name
<int> <int> <chr> <chr>
1 1 1 UA United Air Lines Inc.
2 1 1 UA United Air Lines Inc.
3 1 1 AA American Airlines Inc.
4 1 1 B6 JetBlue Airways
5 1 1 DL Delta Air Lines Inc.
6 1 1 UA United Air Lines Inc.
7 1 1 B6 JetBlue Airways
8 1 1 EV ExpressJet Airlines Inc.
9 1 1 B6 JetBlue Airways
10 1 1 AA American Airlines Inc.
On voit que la table obtenue est bien la fusion des deux tables
d’origine selon les valeurs des deux colonnes clés carrier. On est
parti de la table flights, et pour chaque ligne on a ajouté les
colonnes de airlines pour lesquelles la valeur de carrier est la
même. On a donc bien une nouvelle colonne name dans notre
table résultat, avec le nom complet de la compagnie aérienne.
540
Ĺ Note
Error in `left_join()`:
! `by` must be supplied when `x` and `y` have no common variables.
541
i Use `cross_join()` to perform a cross-join.
flights_ex |>
left_join(airports_ex, by = c("origin" = "faa")) |>
head(10)
# A tibble: 10 x 6
month day origin dest alt name
<int> <int> <chr> <chr> <dbl> <chr>
1 1 1 EWR IAH 18 Newark Liberty Intl
2 1 1 LGA IAH 22 La Guardia
3 1 1 JFK MIA 13 John F Kennedy Intl
4 1 1 JFK BQN 13 John F Kennedy Intl
5 1 1 LGA ATL 22 La Guardia
6 1 1 EWR ORD 18 Newark Liberty Intl
7 1 1 EWR FLL 18 Newark Liberty Intl
8 1 1 LGA IAD 22 La Guardia
9 1 1 JFK MCO 13 John F Kennedy Intl
10 1 1 LGA ORD 22 La Guardia
542
flights_ex |>
left_join(airports_ex, by=c("dest" = "faa")) |>
head(10)
# A tibble: 10 x 8
month day origin dest alt.x name.x alt.y name.y
<int> <int> <chr> <chr> <dbl> <chr> <dbl> <chr>
1 1 1 EWR IAH 18 Newark Liberty Intl 97 George Bush Interco~
2 1 1 LGA IAH 22 La Guardia 97 George Bush Interco~
3 1 1 JFK MIA 13 John F Kennedy Intl 8 Miami Intl
4 1 1 JFK BQN 13 John F Kennedy Intl NA <NA>
5 1 1 LGA ATL 22 La Guardia 1026 Hartsfield Jackson ~
6 1 1 EWR ORD 18 Newark Liberty Intl 668 Chicago Ohare Intl
7 1 1 EWR FLL 18 Newark Liberty Intl 9 Fort Lauderdale Hol~
8 1 1 LGA IAD 22 La Guardia 313 Washington Dulles I~
9 1 1 JFK MCO 13 John F Kennedy Intl 96 Orlando Intl
10 1 1 LGA ORD 22 La Guardia 668 Chicago Ohare Intl
flights_ex |>
left_join(
airports_ex,
by = c("dest" = "faa"),
suffix = c("_depart", "_arrivee")
) |>
head(10)
543
# A tibble: 10 x 8
month day origin dest alt_depart name_depart alt_arrivee name_arrivee
<int> <int> <chr> <chr> <dbl> <chr> <dbl> <chr>
1 1 1 EWR IAH 18 Newark Liberty ~ 97 George Bush~
2 1 1 LGA IAH 22 La Guardia 97 George Bush~
3 1 1 JFK MIA 13 John F Kennedy ~ 8 Miami Intl
4 1 1 JFK BQN 13 John F Kennedy ~ NA <NA>
5 1 1 LGA ATL 22 La Guardia 1026 Hartsfield ~
6 1 1 EWR ORD 18 Newark Liberty ~ 668 Chicago Oha~
7 1 1 EWR FLL 18 Newark Liberty ~ 9 Fort Lauder~
8 1 1 LGA IAD 22 La Guardia 313 Washington ~
9 1 1 JFK MCO 13 John F Kennedy ~ 96 Orlando Intl
10 1 1 LGA ORD 22 La Guardia 668 Chicago Oha~
# A tibble: 6 x 2
nom voiture
<chr> <chr>
1 Sylvie Twingo
2 Sylvie Ferrari
3 Monique Scenic
4 Gunter Lada
5 Rayan Twingo
6 Rayan Clio
544
voitures <- tibble(
voiture = c("Twingo", "Ferrari", "Clio", "Lada", "208"),
vitesse = c("140", "280", "160", "85", "160")
)
voitures
# A tibble: 5 x 2
voiture vitesse
<chr> <chr>
1 Twingo 140
2 Ferrari 280
3 Clio 160
4 Lada 85
5 208 160
33.1.3.1 left_join()
# A tibble: 6 x 3
nom voiture vitesse
<chr> <chr> <chr>
1 Sylvie Twingo 140
2 Sylvie Ferrari 280
3 Monique Scenic <NA>
4 Gunter Lada 85
5 Rayan Twingo 140
6 Rayan Clio 160
545
La clé de fusion étant unique dans la table de droite, le nombre
de lignes de la table de gauche est donc bien préservée.
[1] 6
[1] 6
# A tibble: 6 x 3
voiture vitesse nom
<chr> <chr> <chr>
1 Twingo 140 Sylvie
2 Twingo 140 Rayan
3 Ferrari 280 Sylvie
4 Clio 160 Rayan
5 Lada 85 Gunter
6 208 160 <NA>
La ligne 208 est bien là avec la variable nom remplie avec une
valeur manquante NA. Par contre Monique est absente.
ĺ Important
546
En résumé, quand on fait un left_join(x, y),
toutes les lignes de x sont présentes, et dupliquées
si nécessaire quand elles apparaissent plusieurs fois
dans y. Les lignes de y non présentes dans x dis-
paraissent. Les lignes de x non présentes dans y se
voient attribuer des valeurs manquantes NA pour
les nouvelles colonnes.
33.1.3.2 right_join()
# A tibble: 6 x 3
nom voiture vitesse
<chr> <chr> <chr>
1 Sylvie Twingo 140
2 Sylvie Ferrari 280
3 Gunter Lada 85
4 Rayan Twingo 140
5 Rayan Clio 160
6 <NA> 208 160
# A tibble: 6 x 3
voiture vitesse nom
<chr> <chr> <chr>
1 Twingo 140 Sylvie
547
2 Twingo 140 Rayan
3 Ferrari 280 Sylvie
4 Clio 160 Rayan
5 Lada 85 Gunter
6 208 160 <NA>
33.1.3.3 inner_join()
# A tibble: 5 x 3
nom voiture vitesse
<chr> <chr> <chr>
1 Sylvie Twingo 140
2 Sylvie Ferrari 280
3 Gunter Lada 85
4 Rayan Twingo 140
5 Rayan Clio 160
Ici la ligne 208 est absente, ainsi que la ligne Monique, qui dans
le cas d’un dplyr::left_join() avait été conservée et s’était
vue attribuer NA à vitesse.
33.1.3.4 full_join()
# A tibble: 7 x 3
nom voiture vitesse
548
<chr> <chr> <chr>
1 Sylvie Twingo 140
2 Sylvie Ferrari 280
3 Monique Scenic <NA>
4 Gunter Lada 85
5 Rayan Twingo 140
6 Rayan Clio 160
7 <NA> 208 160
# A tibble: 5 x 2
nom voiture
<chr> <chr>
1 Sylvie Twingo
2 Sylvie Ferrari
3 Gunter Lada
4 Rayan Twingo
5 Rayan Clio
# A tibble: 1 x 2
nom voiture
549
<chr> <chr>
1 Monique Scenic
550
personnes |> left_join(voitures)
# A tibble: 6 x 3
nom voiture vitesse
<chr> <chr> <chr>
1 Sylvie Twingo 140
2 Sylvie Ferrari 280
3 Monique Scenic <NA>
4 Gunter Lada 85
5 Rayan Twingo 140
6 Rayan Clio 160
# A tibble: 2 x 4
faa name lat lon
551
<chr> <chr> <dbl> <dbl>
1 04G Lansdowne Airport 41.1 -80.6
2 06A Moton Field Municipal Airport 32.5 -85.7
t2
# A tibble: 2 x 4
name faa lon lat
<chr> <chr> <dbl> <dbl>
1 Jekyll Island Airport 09J -81.4 31.1
2 Elizabethton Municipal Airport 0A9 -82.2 36.4
# A tibble: 2 x 2
faa name
<chr> <chr>
1 ADW Andrews Afb
2 AET Allakaket Airport
# A tibble: 6 x 4
faa name lat lon
<chr> <chr> <dbl> <dbl>
1 04G Lansdowne Airport 41.1 -80.6
2 06A Moton Field Municipal Airport 32.5 -85.7
3 09J Jekyll Island Airport 31.1 -81.4
552
4 0A9 Elizabethton Municipal Airport 36.4 -82.2
5 ADW Andrews Afb NA NA
6 AET Allakaket Airport NA NA
# A tibble: 6 x 5
source faa name lat lon
<chr> <chr> <chr> <dbl> <dbl>
1 1 04G Lansdowne Airport 41.1 -80.6
2 1 06A Moton Field Municipal Airport 32.5 -85.7
3 2 09J Jekyll Island Airport 31.1 -81.4
4 2 0A9 Elizabethton Municipal Airport 36.4 -82.2
5 3 ADW Andrews Afb NA NA
6 3 AET Allakaket Airport NA NA
# A tibble: 6 x 5
source faa name lat lon
553
<chr> <chr> <chr> <dbl> <dbl>
1 table1 04G Lansdowne Airport 41.1 -80.6
2 table1 06A Moton Field Municipal Airport 32.5 -85.7
3 table2 09J Jekyll Island Airport 31.1 -81.4
4 table2 0A9 Elizabethton Municipal Airport 36.4 -82.2
5 table3 ADW Andrews Afb NA NA
6 table3 AET Allakaket Airport NA NA
554
34 Dates avec lubridate
library(tidyverse)
library(nycflights13)
555
Les classes Date et POSIXct sont gérées nativement par R
tandis que la classe hms est fournies par le package homonyme
{hms}. Cette dernière classe est d’un usage plus spécifique.
Dans cette section, nous allons nous concentrer sur les dates
et les dates-heures.
Il est toujours préférable d’utiliser la classe la plus simple. Si
vous gérez uniquement des dates, privilégiez la classe Date. La
classe POSIXct, plus complexe, permet d’ajouter une heure as-
sociée à un fuseau horaire.
Pour obtenir la date ou la date-heure courante, vous pouvez
appeler today() ou now() :
today()
[1] "2023-11-06"
now()
# A tibble: 1 x 2
date datetime
<date> <dttm>
1 2022-01-02 2022-01-02 05:12:00
556
Ď Astuce
1
https://xkcd.com/1179/
557
Type Code Signification Exemple
%z décalage du fuseau par +0800
rapport au temps universel
UTC
Autre %. sauter un caractère (autre :
qu’un chiffre)
%* sauter un nombre
quelconque de caractères
(autres qu’un chiffre)
# A tibble: 1 x 1
date
<date>
1 2015-01-02
# A tibble: 1 x 1
date
<date>
1 2015-02-01
# A tibble: 1 x 1
date
558
<date>
1 2001-02-15
Quel que soit le format original, les dates importées seront tou-
jours affichées par R au format ISO.
Ď Astuce
date_names_langs()
[1] "af" "agq" "ak" "am" "ar" "as" "asa" "az" "bas" "be" "bem" "bez"
[13] "bg" "bm" "bn" "bo" "br" "brx" "bs" "ca" "cgg" "chr" "cs" "cy"
[25] "da" "dav" "de" "dje" "dsb" "dua" "dyo" "dz" "ebu" "ee" "el" "en"
[37] "eo" "es" "et" "eu" "ewo" "fa" "ff" "fi" "fil" "fo" "fr" "fur"
[49] "fy" "ga" "gd" "gl" "gsw" "gu" "guz" "gv" "ha" "haw" "he" "hi"
[61] "hr" "hsb" "hu" "hy" "id" "ig" "ii" "is" "it" "ja" "jgo" "jmc"
[73] "ka" "kab" "kam" "kde" "kea" "khq" "ki" "kk" "kkj" "kl" "kln" "km"
[85] "kn" "ko" "kok" "ks" "ksb" "ksf" "ksh" "kw" "ky" "lag" "lb" "lg"
[97] "lkt" "ln" "lo" "lt" "lu" "luo" "luy" "lv" "mas" "mer" "mfe" "mg"
[109] "mgh" "mgo" "mk" "ml" "mn" "mr" "ms" "mt" "mua" "my" "naq" "nb"
[121] "nd" "ne" "nl" "nmg" "nn" "nnh" "nus" "nyn" "om" "or" "os" "pa"
[133] "pl" "ps" "pt" "qu" "rm" "rn" "ro" "rof" "ru" "rw" "rwk" "sah"
[145] "saq" "sbp" "se" "seh" "ses" "sg" "shi" "si" "sk" "sl" "smn" "sn"
[157] "so" "sq" "sr" "sv" "sw" "ta" "te" "teo" "th" "ti" "to" "tr"
[169] "twq" "tzm" "ug" "uk" "ur" "uz" "vai" "vi" "vun" "wae" "xog" "yav"
[181] "yi" "yo" "zgh" "zh" "zu"
date_names_lang("fr")
<date_names>
Days: dimanche (dim.), lundi (lun.), mardi (mar.), mercredi (mer.), jeudi
559
(jeu.), vendredi (ven.), samedi (sam.)
Months: janvier (janv.), février (févr.), mars (mars), avril (avr.), mai (mai),
juin (juin), juillet (juil.), août (août), septembre (sept.),
octobre (oct.), novembre (nov.), décembre (déc.)
AM/PM: AM/PM
date_names_lang("en")
<date_names>
Days: Sunday (Sun), Monday (Mon), Tuesday (Tue), Wednesday (Wed), Thursday
(Thu), Friday (Fri), Saturday (Sat)
Months: January (Jan), February (Feb), March (Mar), April (Apr), May (May),
June (Jun), July (Jul), August (Aug), September (Sep), October
(Oct), November (Nov), December (Dec)
AM/PM: AM/PM
read_csv(
csv,
col_types = cols(date = col_date("%d de %B de %Y")),
locale = locale("es")
)
# A tibble: 1 x 1
date
<date>
1 2001-02-03
560
et le jour apparaissent dans vos dates, puis placez “y”, “m” et
“d” dans le même ordre. Cela vous donne le nom de la fonction
{lubridate} qui analysera votre date. Par exemple :
ymd("2017-01-31")
[1] "2017-01-31"
[1] "2017-01-31"
dmy("31-Jan-2017")
[1] "2017-01-31"
ymd_hms("2017-01-31 20:11:59")
mdy_hm("01/31/2017 08:01")
561
flights |>
select(year, month, day, hour, minute) |>
head()
# A tibble: 6 x 5
year month day hour minute
<int> <int> <int> <dbl> <dbl>
1 2013 1 1 5 15
2 2013 1 1 5 29
3 2013 1 1 5 40
4 2013 1 1 5 45
5 2013 1 1 6 0
6 2013 1 1 5 58
flights |>
select(year, month, day, hour, minute) |>
mutate(
departure = make_datetime(year, month, day, hour, minute),
departure_date = make_date(year, month, day)
) |>
head()
# A tibble: 6 x 7
year month day hour minute departure departure_date
<int> <int> <int> <dbl> <dbl> <dttm> <date>
1 2013 1 1 5 15 2013-01-01 05:15:00 2013-01-01
2 2013 1 1 5 29 2013-01-01 05:29:00 2013-01-01
3 2013 1 1 5 40 2013-01-01 05:40:00 2013-01-01
4 2013 1 1 5 45 2013-01-01 05:45:00 2013-01-01
5 2013 1 1 6 0 2013-01-01 06:00:00 2013-01-01
6 2013 1 1 5 58 2013-01-01 05:58:00 2013-01-01
562
34.1.4 conversion
as_datetime(today())
as_date(now())
[1] "2023-11-06"
year(datetime)
[1] 2026
month(datetime)
[1] 7
563
mday(datetime)
[1] 8
yday(datetime)
[1] 189
wday(datetime)
[1] 4
[1] juil
12 Levels: janv < févr < mars < avr < mai < juin < juil < août < ... < déc
[1] mercredi
7 Levels: dimanche < lundi < mardi < mercredi < jeudi < ... < samedi
564
month(datetime, label = TRUE, abbr = FALSE, locale = "en")
[1] July
12 Levels: January < February < March < April < May < June < ... < December
[1] julio
12 Levels: enero < febrero < marzo < abril < mayo < junio < ... < diciembre
[1] Juli
12 Levels: Januar < Februar < März < April < Mai < Juni < Juli < ... < Dezember
34.2.2 Arrondis
d <- ymd("2022-05-14")
floor_date(d, unit = "week")
[1] "2022-05-08"
[1] "2022-05-01"
565
floor_date(d, unit = "3 months")
[1] "2022-04-01"
[1] "2022-01-01"
month(datetime) <- 01
datetime
566
update(datetime, year = 2030, month = 2, mday = 2, hour = 2)
[1] "2023-03-02"
567
diff <- ymd("2021-06-30") - ymd("1979-10-14")
diff
as.duration(diff)
dseconds(15)
[1] "15s"
dminutes(10)
dhours(c(12, 24))
ddays(0:5)
568
dweeks(3)
dyears(1)
2 * dyears(1)
569
one_am <- ymd_hms("2026-03-08 01:00:00", tz = "America/New_York")
one_am
one_am + ddays(1)
one_am
one_am + days(1)
570
Comme pour les durées, on peut créer facilement des périodes
avec des fonctions dédiées (notez ici le pluriel des noms de fonc-
tion, alors que celles permettant d’extraire un composant d’une
date étaient au singulier) :
hours(c(12, 24))
days(7)
months(1:6)
10 * (months(6) + days(1))
571
ymd("2024-01-01") + years(1)
[1] "2025-01-01"
one_am + days(1)
ymd("2021-01-31") + months(1)
[1] NA
[1] "2021-02-28"
572
34.3.3 Intervalles (Interval)
interval(ymd("2022-05-13"), ymd("2022-08-15"))
y2023
y2024
573
[1] TRUE
[1] TRUE
[1] FALSE
int_overlaps(int3, int)
[1] TRUE
intersect(int3, int)
int
574
int_start(int)
int_end(int)
int_flip(int)
[1] 31536000
[1] 52.14286
[1] 365
575
34.4 Calcul d’un âge
[1] 42.62466
[1] 42
576
age_atteint <- year(evt) - year(naiss)
age_atteint
[1] 43
Ď Astuce
577
raison en est que la base de données de l’IANA doit enregistrer
des dizaines d’années de règles relatives aux fuseaux horaires.
Au fil des décennies, les pays changent de nom (ou se séparent)
assez fréquemment, mais les noms de villes ont tendance à res-
ter inchangés. Un autre problème réside dans le fait que le nom
doit refléter non seulement le comportement actuel, mais aussi
l’ensemble de l’histoire. Par exemple, il existe des fuseaux ho-
raires pour "America/New_York" et "America/Detroit". Cela
vaut la peine de lire la base de données brute des fuseaux ho-
raires (disponible à l’adresse https://www.iana.org/time-zones)
rien que pour lire certaines de ces histoires !
Vous pouvez découvrir ce que R pense être votre fuseau horaire
actuel avec Sys.timezone() :
Sys.timezone()
[1] "Europe/Paris"
length(OlsonNames())
[1] 596
head(OlsonNames())
578
x2 <- ymd_hms("2024-06-01 18:00:00", tz = "Europe/Copenhagen")
x2
579
[1] "2024-06-02 02:30:00 +1030" "2024-06-02 02:30:00 +1030"
[3] "2024-06-02 02:30:00 +1030"
x4a - x4
x4b - x4
580
35 Chaînes de texte avec
stringr
library(tidyverse)
Ĺ Note
d <- tibble(
nom = c(
"Mr Félicien Machin", "Mme Raymonde Bidule",
"M. Martial Truc", "Mme Huguette Chose"
),
adresse = c(
"3 rue des Fleurs", "47 ave de la Libération",
"12 rue du 17 octobre 1961", "221 avenue de la Libération"
581
),
ville = c("Nouméa", "Marseille", "Vénissieux", "Marseille")
)
paste(d$adresse, d$ville)
582
Il existe une variante, paste0(), qui concatène sans mettre de
séparateur, et qui est légèrement plus rapide :
paste0(d$adresse, d$ville)
Ĺ Note
paste(d$ville)
583
mettre en minuscules, mettre en majuscules, ou de capitaliser
les éléments d’un vecteur de chaînes de caractères :
[1] "mr félicien machin" "mme raymonde bidule" "m. martial truc"
[4] "mme huguette chose"
[1] "MR FÉLICIEN MACHIN" "MME RAYMONDE BIDULE" "M. MARTIAL TRUC"
[4] "MME HUGUETTE CHOSE"
[1] "Mr Félicien Machin" "Mme Raymonde Bidule" "M. Martial Truc"
[4] "Mme Huguette Chose"
"un-deux-trois" |>
str_split("-")
[[1]]
[1] "un" "deux" "trois"
584
[[1]]
[1] "Mr" "Félicien" "Machin"
[[2]]
[1] "Mme" "Raymonde" "Bidule"
[[3]]
[1] "M." "Martial" "Truc"
[[4]]
[1] "Mme" "Huguette" "Chose"
d$nom |>
str_split(" ", simplify = TRUE)
d |>
tidyr::separate(
col = nom,
into = c("genre", "prenom", "nom")
)
585
# A tibble: 4 x 5
genre prenom nom adresse ville
<chr> <chr> <chr> <chr> <chr>
1 Mr F licien 3 rue des Fleurs Nouméa
2 Mme Raymonde Bidule 47 ave de la Libération Marseille
3 M Martial Truc 12 rue du 17 octobre 1961 Vénissieux
4 Mme Huguette Chose 221 avenue de la Libération Marseille
d |>
filter(adresse |> str_detect("Libération"))
586
# A tibble: 2 x 3
nom adresse ville
<chr> <chr> <chr>
1 Mme Raymonde Bidule 47 ave de la Libération Marseille
2 Mme Huguette Chose 221 avenue de la Libération Marseille
d$ville
[1] 0 1 2 1
ĺ Important
587
35.6 Expressions régulières
d$adresse |>
str_extract("Libération")
588
[1] "3" "47" "12" "221"
[[1]]
[1] "3"
[[2]]
[1] "47"
[[3]]
[1] "12" "17" "1961"
[[4]]
[1] "221"
d |>
tidyr::extract(
col = adresse,
into = "type_rue",
regex = "^\\d+ (.*?) ",
remove = FALSE
)
589
# A tibble: 4 x 4
nom adresse type_rue ville
<chr> <chr> <chr> <chr>
1 Mr Félicien Machin 3 rue des Fleurs rue Nouméa
2 Mme Raymonde Bidule 47 ave de la Libération ave Marseille
3 M. Martial Truc 12 rue du 17 octobre 1961 rue Vénissieux
4 Mme Huguette Chose 221 avenue de la Libération avenue Marseille
d$nom |>
str_replace("Mr", "M.")
[1] "M. Félicien Machin" "Mme Raymonde Bidule" "M. Martial Truc"
[4] "Mme Huguette Chose"
d$adresse |>
str_replace_all(
c(
"avenue"="Avenue",
"ave"="Avenue",
"rue"="Rue"
)
)
590
35.9 Modificateurs de motifs
[1] 18 19 15 18
Il faut donc spécifier que notre point est bien un point avec
stringr::fixed() :
[1] 0 0 1 0
d$nom |>
str_detect(regex("mme", ignore_case = TRUE))
591
On peut également permettre aux expressions régulières d’être
multilignes avec l’option multiline = TRUE, etc.
Je m'appelle Fred. L'année prochaine j'aurai 29 ans, car je suis né le samedi 12 octobre 1991.
592
35.11 Ressources
593
36 Réorganisation avec tidyr
Comme indiqué dans le chapitre sur les tibbles (cf. Chapitre 5),
les extensions du tidyverse comme {dplyr} ou {ggplot2}
partent du principe que les données sont “bien rangées” sous
forme de tidy data.
Prenons un exemple avec les données suivantes, qui indique la
population de trois pays pour quatre années différentes :
594
country year population
Germany 2002 82350671
Germany 2007 82400996
library(tidyverse)
ggplot(d) +
aes(x = year, y = population, color = country) +
geom_line() +
scale_x_continuous(breaks = unique(d$year)) +
scale_y_continuous(
labels = scales::label_number(
scale = 10^-6,
suffix = " millions"
)
)
80 millions
60 millions
country
population
Belgium
France
40 millions
Germany
20 millions
595
d |>
group_by(country) |>
summarise(pop_min = min(population))
# A tibble: 3 x 2
country pop_min
<fct> <int>
1 Belgium 10045622
2 France 57374179
3 Germany 80597764
596
le pays, l’année et la population. Or elles ne correspondent pas
aux colonnes de la table. C’est le cas par contre pour la table
transformée :
597
year monthday dep_time
carrier name flights_per_year
2013 1 1 558 AA American 32729
Airlines Inc.
2013 1 1 558 UA United Air 58665
Lines Inc.
2013 1 1 558 UA United Air 58665
Lines Inc.
2013 1 1 559 AA American 32729
Airlines Inc.
598
dupliquée, et on peut facilement faire une jointure si on a besoin
de récupérer l’information d’une table dans une autre.
L’objectif de {tidyr} est de fournir des fonctions pour arran-
ger ses données et les convertir dans un format tidy. Ces fonc-
tions prennent la forme de verbes qui viennent compléter ceux
de {dplyr} et s’intègrent parfaitement dans les séries de pipes
(|>, cf. Chapitre 7), les pipelines, permettant d’enchaîner les
opérations.
d |>
pivot_longer(
cols = c(`2002`,`2007`),
names_to = "annee",
values_to = "population"
)
599
# A tibble: 8 x 3
country annee population
<fct> <chr> <int>
1 Belgium 2002 10311970
2 Belgium 2007 10392226
3 France 2002 59925035
4 France 2007 61083916
5 Germany 2002 82350671
6 Germany 2007 82400996
7 Spain 2002 40152517
8 Spain 2007 40448191
d |>
pivot_longer(
-country,
names_to = "annee",
values_to = "population"
)
# A tibble: 8 x 3
country annee population
<fct> <chr> <int>
1 Belgium 2002 10311970
2 Belgium 2007 10392226
600
3 France 2002 59925035
4 France 2007 61083916
5 Germany 2002 82350671
6 Germany 2007 82400996
7 Spain 2002 40152517
8 Spain 2007 40448191
d |>
pivot_wider(
names_from = variable,
values_from = value
601
)
# A tibble: 6 x 5
country continent year lifeExp pop
<fct> <fct> <int> <dbl> <dbl>
1 Belgium Europe 2002 78.3 10311970
2 Belgium Europe 2007 79.4 10392226
3 France Europe 2002 79.6 59925035
4 France Europe 2007 80.7 61083916
5 Germany Europe 2002 78.7 82350671
6 Germany Europe 2007 79.4 82400996
602
country continent year variable value
France Europe 2002 density 94.000
d |>
pivot_wider(
names_from = variable,
values_from = value
)
# A tibble: 6 x 6
country continent year lifeExp pop density
<chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 Belgium Europe 2002 78.3 10311970 NA
2 Belgium Europe 2007 79.4 10392226 NA
3 France Europe 2002 79.6 59925035 94
4 France Europe 2007 80.7 61083916 NA
5 Germany Europe 2002 78.7 82350671 NA
6 Germany Europe 2007 79.4 82400996 NA
d |>
pivot_wider(
names_from = variable,
values_from = value,
values_fill = list(value = 0)
)
# A tibble: 6 x 6
country continent year lifeExp pop density
<chr> <chr> <dbl> <dbl> <dbl> <dbl>
1 Belgium Europe 2002 78.3 10311970 0
2 Belgium Europe 2007 79.4 10392226 0
3 France Europe 2002 79.6 59925035 94
4 France Europe 2007 80.7 61083916 0
5 Germany Europe 2002 78.7 82350671 0
6 Germany Europe 2007 79.4 82400996 0
603
36.5 separate() : séparer une colonne en
plusieurs colonnes
df <- tibble(
eleve = c("Alex Petit", "Bertrand Dupont", "Corinne Durand"),
note = c("5/20", "6/10", "87/100")
)
df
# A tibble: 3 x 2
eleve note
<chr> <chr>
1 Alex Petit 5/20
2 Bertrand Dupont 6/10
3 Corinne Durand 87/100
df |>
separate(note, c("note", "note_sur"))
# A tibble: 3 x 3
eleve note note_sur
<chr> <chr> <chr>
1 Alex Petit 5 20
2 Bertrand Dupont 6 10
3 Corinne Durand 87 100
604
df |>
tidyr::separate(
eleve,
c("prenom", "nom"),
sep = " "
)
# A tibble: 3 x 3
prenom nom note
<chr> <chr> <chr>
1 Alex Petit 5/20
2 Bertrand Dupont 6/10
3 Corinne Durand 87/100
df <- tibble(
eleve = c("Alex Petit", "Bertrand Dupont", "Corinne Durand"),
notes = c("10,15,16", "18,12,14", "16,17")
)
df
# A tibble: 3 x 2
eleve notes
<chr> <chr>
1 Alex Petit 10,15,16
2 Bertrand Dupont 18,12,14
3 Corinne Durand 16,17
605
Appliquons tidyr::separate_rows().
df |>
separate_rows(notes) |>
rename(note = notes)
# A tibble: 8 x 2
eleve note
<chr> <chr>
1 Alex Petit 10
2 Alex Petit 15
3 Alex Petit 16
4 Bertrand Dupont 18
5 Bertrand Dupont 12
6 Bertrand Dupont 14
7 Corinne Durand 16
8 Corinne Durand 17
df |>
separate_rows(notes, sep = ",") |>
rename(note = notes)
# A tibble: 8 x 2
eleve note
<chr> <chr>
1 Alex Petit 10
2 Alex Petit 15
3 Alex Petit 16
4 Bertrand Dupont 18
5 Bertrand Dupont 12
6 Bertrand Dupont 14
7 Corinne Durand 16
8 Corinne Durand 17
606
36.7 unite() : regrouper plusieurs colonnes
en une seule
d |>
unite(code_insee, code_departement, code_commune)
# A tibble: 6 x 3
code_insee commune pop_tot
<chr> <chr> <int>
1 01_004 Ambérieu-en-Bugey 14233
2 01_007 Ambronay 2437
3 01_014 Arbent 3440
4 01_024 Attignat 3110
5 01_025 Bâgé-la-Ville 3130
6 01_027 Balan 2785
607
résoudre ces deux problèmes à l’aide des arguments sep et
remove :
d |>
unite(
code_insee,
code_departement,
code_commune,
sep = "",
remove = FALSE
)
# A tibble: 6 x 5
code_insee code_departement code_commune commune pop_tot
<chr> <chr> <chr> <chr> <int>
1 01004 01 004 Ambérieu-en-Bugey 14233
2 01007 01 007 Ambronay 2437
3 01014 01 014 Arbent 3440
4 01024 01 024 Attignat 3110
5 01025 01 025 Bâgé-la-Ville 3130
6 01027 01 027 Balan 2785
eleve note
Alex Petit 5/20
Bertrand Dupont 6/10
Corinne Durand 87/100
608
df |>
extract(
eleve,
c("prenom", "nom"),
"^(.*) (.*)$"
)
# A tibble: 3 x 3
prenom nom note
<chr> <chr> <chr>
1 Alex Petit 5/20
2 Bertrand Dupont 6/10
3 Corinne Durand 87/100
df |>
tidyr::extract(
eleve,
c("initiale_prenom", "initiale_nom"),
"^(.).* (.).*$",
remove = FALSE
)
# A tibble: 3 x 4
eleve initiale_prenom initiale_nom note
<chr> <chr> <chr> <chr>
1 Alex Petit A P 5/20
2 Bertrand Dupont B D 6/10
3 Corinne Durand C D 87/100
609
36.9 complete() : compléter des
combinaisons de variables manquantes
df |>
complete(eleve, matiere)
# A tibble: 6 x 3
eleve matiere note
<chr> <chr> <dbl>
1 Alain Français 9
2 Alain Maths 16
3 Barnabé Français NA
4 Barnabé Maths 17
5 Chantal Français 11
6 Chantal Maths NA
610
Par défaut les lignes insérées récupèrent des valeurs manquantes
NA pour les colonnes restantes. On peut néanmoins choisir une
autre valeur avec l’argument fill, qui prend la forme d’une
liste nommée :
df |>
complete(
eleve,
matiere,
fill = list(note = 0)
)
# A tibble: 6 x 3
eleve matiere note
<chr> <chr> <dbl>
1 Alain Français 9
2 Alain Maths 16
3 Barnabé Français 0
4 Barnabé Maths 17
5 Chantal Français 11
6 Chantal Maths 0
611
df |>
complete(eleve, matiere)
# A tibble: 6 x 4
eleve matiere id note
<chr> <chr> <dbl> <dbl>
1 Alain Français 1001001 9
2 Alain Maths 1001001 16
3 Barnabé Français NA NA
4 Barnabé Maths 1001002 17
5 Chantal Français 1001003 11
6 Chantal Maths NA NA
df |>
complete(id, eleve, matiere)
# A tibble: 18 x 4
id eleve matiere note
<dbl> <chr> <chr> <dbl>
1 1001001 Alain Français 9
2 1001001 Alain Maths 16
3 1001001 Barnabé Français NA
4 1001001 Barnabé Maths NA
5 1001001 Chantal Français NA
6 1001001 Chantal Maths NA
7 1001002 Alain Français NA
8 1001002 Alain Maths NA
9 1001002 Barnabé Français NA
10 1001002 Barnabé Maths 17
11 1001002 Chantal Français NA
12 1001002 Chantal Maths NA
13 1001003 Alain Français NA
14 1001003 Alain Maths NA
15 1001003 Barnabé Français NA
16 1001003 Barnabé Maths NA
17 1001003 Chantal Français 11
612
18 1001003 Chantal Maths NA
df |>
complete(
nesting(id, eleve),
matiere
)
# A tibble: 6 x 4
id eleve matiere note
<dbl> <chr> <chr> <dbl>
1 1001001 Alain Français 9
2 1001001 Alain Maths 16
3 1001002 Barnabé Français NA
4 1001002 Barnabé Maths 17
5 1001003 Chantal Français 11
6 1001003 Chantal Maths NA
36.10 Ressources
613
Le site de l’extension est accessible à l’adresse : http://tidyr.
tidyverse.org/ et contient une liste des fonctions et les pages
d’aide associées.
En particulier, on pourra se référer à la vignette dédiée à
tidyr::pivot_wider() et tidyr::pivot_longer() pour des
exemples avancés de réorganisation des données.
Pour des usages avancés, il est possible avec {tidyr} de gérer
des données nichées (nested data), c’est-à-dire des tableaux de
données dans des tableaux de données. Ces fonctionnalités, ré-
servées aux utilisateurs avancés, sont décrites dans une vignette
spécifique.
36.12 webin-R
614
37 Conditions logiques
x <- c(1, 5, 2, 8)
x < 3
y <- c(3, 5, 1, 7)
y >= x
615
[1] TRUE TRUE FALSE FALSE
y == x
y != x
library(tidyverse)
[1] 2000
hdv2003 |>
filter(sexe == "Femme") |>
nrow()
[1] 1101
616
hdv2003 |>
filter(age < 25) |>
nrow()
[1] 169
x <- 1 / 49 * 49
x
[1] 1
x == 1
[1] FALSE
[1] 0.9999999999999999
near(x, 1)
[1] TRUE
617
On peut aussi utiliser cette fonction en personnalisant le
niveau de tolérance pour la comparaison.
2 < NA
[1] NA
NA == 6
[1] NA
d <- tibble(
a = c(1, NA, 3, 4),
b = c("x", "y", "x", "y")
)
d[d$a > 2, ]
# A tibble: 3 x 2
a b
<dbl> <chr>
1 NA <NA>
2 3 x
3 4 y
618
Le recours à dplyr::filter() est plus sûr car les lignes pour
lesquelles la condition renvoie NA ne sont pas sélectionnées.
# A tibble: 2 x 2
a b
<dbl> <chr>
1 3 x
2 4 y
d$a == NA
[1] NA NA NA NA
is.na(d$a)
Ď Astuce
619
is_different <- function(x, y) {
(x != y & !is.na(x) & !is.na(y)) | xor(is.na(x), is.na(y))
}
v == w
is_equal(v, w)
v != w
is_different(v, w)
620
• | : opérateur ou (x | y est vrai si x ou y ou les deux sont
vrais) ;
• xor() : opérateur ou exclusif (xor(x, y) est vrai si seule-
ment x ou seulement y est vrai, mais pas les deux) ;
• ! : opérateur non (!x est vrai si x est faux).
hdv2003 |>
filter(sexe == "Femme" & age < 25) |>
nrow()
[1] 93
hdv2003 |>
filter(sexe == "Femme" | age < 25) |>
nrow()
[1] 1177
621
# sélectionne les jeunes femmes et les hommes âgés
hdv2003 |>
filter(
(sexe == "Femme" & age < 25) |
(sexe == "Homme" & age > 60)) |>
nrow()
[1] 315
df |>
mutate(
et_na = x & NA,
ou_na = x | NA
)
# A tibble: 3 x 3
x et_na ou_na
<lgl> <lgl> <lgl>
1 TRUE NA TRUE
2 FALSE FALSE NA
3 NA NA NA
TRUE | NA vaut TRUE car la condition reste vrai quelle que soit
la valeur du deuxième paramètre, tandis que FALSE | NA ren-
voie NA car le résultat est indéterminé (il dépend du deuxième
paramètre).
622
37.3.2 L’opérateur %in%
37.4 Aggrégation
[1] TRUE
all(x)
[1] FALSE
623
Un vecteur logique peut-être vu comme un vecteur de valeur
binaire (0 si FALSE, 1 si TRUE). On peut dès lors effectuer des
opérations comme la somme ou la moyenne.
[1] 1
[1] 0.3333333
37.5 Programmation
isTRUE(TRUE)
[1] TRUE
isTRUE(NA)
[1] FALSE
624
isTRUE(NULL)
[1] FALSE
isTRUE(c(TRUE, TRUE))
[1] FALSE
625
38 Transformations multiples
df %>%
group_by(g1, g2) %>%
summarise(
a = mean(a),
b = mean(b),
c = mean(c),
d = mean(d)
)
df %>%
group_by(g1, g2) %>%
summarise(across(a:d, mean))
626
• le second, .fns, est une fonction (ou une liste de fonc-
tions) à appliquer à chaque colonne sélectionnée.
library(tidyverse)
starwars |>
summarise(across(where(is.character), n_distinct))
# A tibble: 1 x 8
name hair_color skin_color eye_color sex gender homeworld species
<int> <int> <int> <int> <int> <int> <int> <int>
1 87 13 31 15 5 3 49 38
starwars |>
group_by(species) |>
filter(n() > 1) |>
summarise(across(c(sex, gender, homeworld), n_distinct))
# A tibble: 9 x 4
species sex gender homeworld
<chr> <int> <int> <int>
1 Droid 1 2 3
2 Gungan 1 1 1
3 Human 2 2 16
627
4 Kaminoan 2 2 1
5 Mirialan 1 1 1
6 Twi'lek 2 2 1
7 Wookiee 1 1 1
8 Zabrak 1 1 2
9 <NA> 1 1 3
starwars %>%
group_by(homeworld) |>
filter(n() > 1) |>
summarise(across(where(is.numeric), mean))
# A tibble: 10 x 4
homeworld height mass birth_year
<chr> <dbl> <dbl> <dbl>
1 Alderaan 176. NA NA
2 Corellia 175 78.5 25
3 Coruscant 174. NA NA
4 Kamino 208. NA NA
5 Kashyyyk 231 124 NA
6 Mirial 168 53.1 49
7 Naboo 175. NA NA
8 Ryloth 179 NA NA
9 Tatooine 170. NA NA
10 <NA> NA NA NA
628
• une formule définissant une fonction dans le style du pa-
ckage purrr, c’est-à-dire une formule commençant par ~
et dont le premier argument sera noté .x57 . 57
Cette syntaxe particulière n’est
compatible que dans certaines fonc-
tions du {tidyverse}. Ce n’est pas
ma_fonction <- function(x) {mean(x, na.rm = TRUE)} une syntaxe standard de R.
starwars %>%
group_by(homeworld) |>
filter(n() > 1) |>
summarise(across(where(is.numeric), ma_fonction))
# A tibble: 10 x 4
homeworld height mass birth_year
<chr> <dbl> <dbl> <dbl>
1 Alderaan 176. 64 43
2 Corellia 175 78.5 25
3 Coruscant 174. 50 91
4 Kamino 208. 83.1 31.5
5 Kashyyyk 231 124 200
6 Mirial 168 53.1 49
7 Naboo 175. 64.2 55
8 Ryloth 179 55 48
9 Tatooine 170. 85.4 54.6
10 <NA> 139. 82 334.
starwars %>%
group_by(homeworld) |>
filter(n() > 1) |>
summarise(across(where(is.numeric), purrr::partial(mean, na.rm = TRUE)))
# A tibble: 10 x 4
homeworld height mass birth_year
<chr> <dbl> <dbl> <dbl>
1 Alderaan 176. 64 43
2 Corellia 175 78.5 25
3 Coruscant 174. 50 91
4 Kamino 208. 83.1 31.5
5 Kashyyyk 231 124 200
6 Mirial 168 53.1 49
7 Naboo 175. 64.2 55
629
8 Ryloth 179 55 48
9 Tatooine 170. 85.4 54.6
10 <NA> 139. 82 334.
starwars %>%
group_by(homeworld) |>
filter(n() > 1) |>
summarise(across(where(is.numeric), \(x) {mean(x, na.rm = TRUE)}))
# A tibble: 10 x 4
homeworld height mass birth_year
<chr> <dbl> <dbl> <dbl>
1 Alderaan 176. 64 43
2 Corellia 175 78.5 25
3 Coruscant 174. 50 91
4 Kamino 208. 83.1 31.5
5 Kashyyyk 231 124 200
6 Mirial 168 53.1 49
7 Naboo 175. 64.2 55
8 Ryloth 179 55 48
9 Tatooine 170. 85.4 54.6
10 <NA> 139. 82 334.
starwars %>%
group_by(homeworld) |>
filter(n() > 1) |>
summarise(across(where(is.numeric), ~ mean(.x, na.rm = TRUE)))
# A tibble: 10 x 4
homeworld height mass birth_year
<chr> <dbl> <dbl> <dbl>
1 Alderaan 176. 64 43
2 Corellia 175 78.5 25
3 Coruscant 174. 50 91
4 Kamino 208. 83.1 31.5
5 Kashyyyk 231 124 200
6 Mirial 168 53.1 49
7 Naboo 175. 64.2 55
630
8 Ryloth 179 55 48
9 Tatooine 170. 85.4 54.6
10 <NA> 139. 82 334.
df <- data.frame(
g = c(1, 1, 2),
x = c(-1, 1, 3),
y = c(-1, -4, -9)
)
df %>%
group_by(g) %>%
summarise(across(where(is.numeric), sum))
# A tibble: 2 x 3
g x y
<dbl> <dbl> <dbl>
1 1 0 -5
2 2 3 -9
# A tibble: 1 x 6
631
height_min height_max mass_min mass_max birth_year_min birth_year_max
<int> <int> <dbl> <dbl> <dbl> <dbl>
1 66 264 15 1358 8 896
starwars |>
summarise(
across(
where(is.numeric),
min_max,
.names = "{.fn}.{.col}"
)
)
# A tibble: 1 x 6
min.height max.height min.mass max.mass min.birth_year max.birth_year
<int> <int> <dbl> <dbl> <dbl> <dbl>
1 66 264 15 1358 8 896
df |>
mutate(
across(
all_of(names(mult)),
~ .x * mult[[cur_column()]]
)
632
)
# A tibble: 3 x 3
x y z
<dbl> <dbl> <dbl>
1 1 30 500
2 2 40 600
3 3 50 700
# A tibble: 4 x 2
x y
<dbl> <dbl>
1 0 0
2 0.333 0.956
3 0.667 1
4 1 0.326
38.1.4 pick()
633
Dans ce cas, nous recommandons d’utiliser le complément
de dplyr::across(), dplyr::pick(), qui fonctionne comme
across() mais n’applique aucune fonction et renvoie à la place
un cadre de données contenant les colonnes sélectionnées.
starwars |>
distinct(pick(contains("color")))
# A tibble: 67 x 3
hair_color skin_color eye_color
<chr> <chr> <chr>
1 blond fair blue
2 <NA> gold yellow
3 <NA> white, blue red
4 none white yellow
5 brown light brown
6 brown, grey light blue
7 brown light blue
8 <NA> white, red red
9 black light brown
10 auburn, white fair blue-gray
# i 57 more rows
starwars |>
count(pick(contains("color")), sort = TRUE)
# A tibble: 67 x 4
hair_color skin_color eye_color n
<chr> <chr> <chr> <int>
1 brown light brown 6
2 brown fair blue 4
3 none grey black 4
4 black dark brown 3
5 blond fair blue 3
6 black fair brown 2
7 black tan brown 2
8 black yellow blue 2
9 brown fair brown 2
10 none white yellow 2
634
# i 57 more rows
starwars |>
filter(if_any(everything(), ~ !is.na(.x)))
# A tibble: 87 x 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke Sk~ 172 77 blond fair blue 19 male mascu~
2 C-3PO 167 75 <NA> gold yellow 112 none mascu~
3 R2-D2 96 32 <NA> white, bl~ red 33 none mascu~
4 Darth V~ 202 136 none white yellow 41.9 male mascu~
5 Leia Or~ 150 49 brown light brown 19 fema~ femin~
6 Owen La~ 178 120 brown, gr~ light blue 52 male mascu~
7 Beru Wh~ 165 75 brown light blue 47 fema~ femin~
8 R5-D4 97 32 <NA> white, red red NA none mascu~
9 Biggs D~ 183 84 black light brown 24 male mascu~
10 Obi-Wan~ 182 77 auburn, w~ fair blue-gray 57 male mascu~
# i 77 more rows
# i 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
635
dplyr::if_all() sélectionne les lignes pour lesquelles le pré-
dicat est vrai pour toutes les colonnes sélectionnées :
starwars |>
filter(if_all(everything(), ~ !is.na(.x)))
# A tibble: 29 x 14
name height mass hair_color skin_color eye_color birth_year sex gender
<chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
1 Luke Sk~ 172 77 blond fair blue 19 male mascu~
2 Darth V~ 202 136 none white yellow 41.9 male mascu~
3 Leia Or~ 150 49 brown light brown 19 fema~ femin~
4 Owen La~ 178 120 brown, gr~ light blue 52 male mascu~
5 Beru Wh~ 165 75 brown light blue 47 fema~ femin~
6 Biggs D~ 183 84 black light brown 24 male mascu~
7 Obi-Wan~ 182 77 auburn, w~ fair blue-gray 57 male mascu~
8 Anakin ~ 188 84 blond fair blue 41.9 male mascu~
9 Chewbac~ 228 112 brown unknown blue 200 male mascu~
10 Han Solo 180 80 brown fair brown 29 male mascu~
# i 19 more rows
# i 5 more variables: homeworld <chr>, species <chr>, films <list>,
# vehicles <list>, starships <list>
38.3.1 Création
636
df <- tibble(x = 1:2, y = 3:4, z = 5:6)
df |> rowwise()
# A tibble: 2 x 3
# Rowwise:
x y z
<int> <int> <int>
1 1 3 5
2 2 4 6
df |>
mutate(m = mean(c(x, y, z)))
# A tibble: 2 x 4
x y z m
<int> <int> <int> <dbl>
1 1 3 5 3.5
2 2 4 6 3.5
df |>
rowwise() |>
mutate(m = mean(c(x, y, z)))
# A tibble: 2 x 4
# Rowwise:
x y z m
<int> <int> <int> <dbl>
1 1 3 5 3
2 2 4 6 4
637
vous l’appliquez à un tableau de données row-wise, il calcule
la moyenne séparément pour chaque ligne.
Vous pouvez optionnellement fournir des variables identifiantes
dans votre appel à rowwise(). Ces variables sont conservées
lorsque vous appelez summarise(), de sorte qu’elles se com-
portent de manière similaire aux variables de regroupement
passées à group_by():
df <- tibble(
name = c("Mara", "Hadley"),
x = 1:2,
y = 3:4,
z = 5:6
)
df |>
rowwise() |>
summarise(m = mean(c(x, y, z)))
# A tibble: 2 x 1
m
<dbl>
1 3
2 4
df |>
rowwise(name) |>
summarise(m = mean(c(x, y, z)))
`summarise()` has grouped output by 'name'. You can override using the
`.groups` argument.
# A tibble: 2 x 2
# Groups: name [2]
name m
<chr> <dbl>
1 Mara 3
2 Hadley 4
638
rowwise() n’est qu’une forme spéciale de regroupement :
donc si vous voulez enlever sa déclaration, appelez simplement
ungroup().
df <- tibble(
id = 1:6,
w = 10:15,
x = 20:25,
y = 30:35,
z = 40:45
)
df
# A tibble: 6 x 5
id w x y z
<int> <int> <int> <int> <int>
1 1 10 20 30 40
2 2 11 21 31 41
3 3 12 22 32 42
4 4 13 23 33 43
5 5 14 24 34 44
6 6 15 25 35 45
df |>
rowwise(id) |>
mutate(total = sum(c(w, x, y, z)))
639
# A tibble: 6 x 6
# Rowwise: id
id w x y z total
<int> <int> <int> <int> <int> <int>
1 1 10 20 30 40 100
2 2 11 21 31 41 104
3 3 12 22 32 42 108
4 4 13 23 33 43 112
5 5 14 24 34 44 116
6 6 15 25 35 45 120
df |>
rowwise(id) |>
summarise(total = sum(c(w, x, y, z)))
`summarise()` has grouped output by 'id'. You can override using the `.groups`
argument.
# A tibble: 6 x 2
# Groups: id [6]
id total
<int> <int>
1 1 100
2 2 104
3 3 108
4 4 112
5 5 116
6 6 120
df |>
rowwise(id) |>
mutate(total = sum(c_across(w:z)))
640
# A tibble: 6 x 6
# Rowwise: id
id w x y z total
<int> <int> <int> <int> <int> <int>
1 1 10 20 30 40 100
2 2 11 21 31 41 104
3 3 12 22 32 42 108
4 4 13 23 33 43 112
5 5 14 24 34 44 116
6 6 15 25 35 45 120
df |>
rowwise(id) |>
mutate(total = sum(c_across(where(is.numeric))))
# A tibble: 6 x 6
# Rowwise: id
id w x y z total
<int> <int> <int> <int> <int> <int>
1 1 10 20 30 40 100
2 2 11 21 31 41 104
3 3 12 22 32 42 108
4 4 13 23 33 43 112
5 5 14 24 34 44 116
6 6 15 25 35 45 120
df |>
rowwise(id) |>
mutate(total = sum(c_across(w:z))) |>
ungroup() |>
mutate(across(w:z, ~ . / total))
# A tibble: 6 x 6
id w x y z total
641
<int> <dbl> <dbl> <dbl> <dbl> <int>
1 1 0.1 0.2 0.3 0.4 100
2 2 0.106 0.202 0.298 0.394 104
3 3 0.111 0.204 0.296 0.389 108
4 4 0.116 0.205 0.295 0.384 112
5 5 0.121 0.207 0.293 0.379 116
6 6 0.125 0.208 0.292 0.375 120
ĺ Important
df |>
mutate(total = rowSums(pick(where(is.numeric), -id)))
# A tibble: 6 x 6
id w x y z total
<int> <int> <int> <int> <int> <dbl>
1 1 10 20 30 40 100
2 2 11 21 31 41 104
3 3 12 22 32 42 108
4 4 13 23 33 43 112
5 5 14 24 34 44 116
6 6 15 25 35 45 120
df |>
mutate(mean = rowMeans(pick(where(is.numeric), -id)))
# A tibble: 6 x 6
id w x y z mean
642
<int> <int> <int> <int> <int> <dbl>
1 1 10 20 30 40 25
2 2 11 21 31 41 26
3 3 12 22 32 42 27
4 4 13 23 33 43 28
5 5 14 24 34 44 29
6 6 15 25 35 45 30
643
partie VI
Analyses avancées
644
39 Analyse factorielle
645
valeurs manquantes : on parle alors d’Analyse des corres-
pondances multiples spécifique qui se calcule avec la fonction
GDAtools::speMCA().
Le package {FactoMineR} propose également deux variantes
avancées : l’analyse factorielle multiple permettant d’organiser
les variables en groupes (fonction FactoMineR::MFA())
et l’analyse factorielle multiple hiérarchique (fonction
FactoMineR::MFA()).
Deux autres packages nous seront particulièrement utiles dans
ce chapitre : {explor} pour une exploration visuelle interactive
des résultats et {factoextra} pour diverses représentations
graphiques.
646
Dès lors, l’analyse pourra se concentrer sur ses premiers axes qui
constitueront un bon résumé des variations observables dans
l’échantillon.
ĺ Important
647
library(tidyverse)
data("hdv2003", package = "questionr")
d <- hdv2003 |>
select(hard.rock:sport)
d |> questionr::freq.na()
missing %
hard.rock 0 0
lecture.bd 0 0
peche.chasse 0 0
cuisine 0 0
bricol 0 0
cinema 0 0
sport 0 0
d |> labelled::look_for()
648
39.2.1 Calcul de l’ACM
Les deux ACM sont ici identiques. Par contre, les deux objets
renvoyés ne sont pas structurés de la même manière.
649
acm1_ad |> explor::explor()
650
Figure 39.1: Exemple de figure exportée à partir de explor
acm1_ad |>
factoextra::get_eigenvalue()
651
Dim.6 0.1192865 11.92865 90.63104
Dim.7 0.0936896 9.36896 100.00000
acm1_ad |>
factoextra::fviz_screeplot()
Scree plot
Percentage of explained variances
20
15
10
0
1 2 3 4 5 6 7
Dimensions
652
de dimension considérée pour ce concentrer sur les principales
associations entre modalités, il est fréquent de se limiter aux
deux premiers ou aux trois premiers axes.
Une approche fréquente consiste à regarder s’il y a un coude,
un saut plus marqué qu’un autre dans le graphique des va-
leurs propres. Dans notre exemple, qui ne comporte qu’un petit
nombre de variable, on voit un saut marqué entre le premier
axe et les autres, suggérant de se focaliser en particulier sur ce
premier axe.
acm1_ad |>
factoextra::fviz_contrib(choice = "var", axes = 1)
20
Contributions (%)
15
10
0
ui
ui
on
on
ui
on
ui
on
ui
ui
ui
on
on
on
t.O
.O
.O
.O
.O
N
t.N
.N
.N
.N
.N
a.
e.
se
a.
ol
e.
bd
ck
se
ol
bd
ck
or
in
m
or
ic
in
m
.ro
as
ic
e.
sp
.ro
is
as
ne
e.
sp
br
is
ne
br
ur
cu
ch
rd
ur
cu
ch
rd
ci
ci
ct
ha
ct
e.
ha
e.
le
le
ch
ch
pe
pe
653
tons ici que le premier axe est surtout déterminé par la pratique
d’une activité sportive et le fait d’aller au cinéma.
acm1_ad |>
factoextra::fviz_contrib(choice = "var", axes = 2)
40
20
0
on
ui
ui
on
ui
on
ui
ui
ui
on
on
ui
on
on
O
.O
t.O
.O
.N
.N
t.N
.N
e.
a.
d.
e.
ol
e.
a.
ck
d.
ne
ol
ck
or
ss
in
m
or
ic
ss
b
ro
ic
e.
sp
.ro
is
si
ne
e.
sp
br
a
ne
br
ha
d.
ur
cu
i
ch
ur
cu
rd
ci
r
ci
ct
c
ha
ct
e.
ha
e.
le
le
ch
ch
pe
pe
654
acm1_ad |>
factoextra::fviz_mca_var()
2
Dim2 (15.4%)
1
bricol.Oui
cinema.Non
cuisine.Oui sport.Non
lecture.bd.Non
hard.rock.Non
0 sport.Oui cuisine.Non
hard.rock.Oui peche.chasse.Non
cinema.Oui bricol.Non
lecture.bd.Oui
Ĺ Note
acm1_fm |>
factoextra::fviz_mca_var()
655
Variable categories − MCA
peche.chasse_Oui
2
Dim2 (15.4%)
1
bricol_Oui
cinema_Non
sport_Non cuisine_Oui
lecture.bd_Non
hard.rock_Non
0 cuisine_Non sport_Oui
peche.chasse_Non hard.rock_Oui
bricol_Non cinema_Oui
lecture.bd_Oui
acm1_ad |>
factoextra::fviz_mca_ind()
656
Individuals − MCA
1067
1066
1114
1147
1146
1215
1489
1604
1745
1779
1806
1836
1841
1901
1904
1997
160
267
353
487
597
708
800
830
853
911
966
8
1987
1003
1503
1810
1866
323
326
393
420
479
784 1076
1159
1169
1176
1420
1479
1513
1543
1711
1732
1918
120
228
290
343
366
406
423
532
548
563
571
697
777
801
33
68
88
281 1893
1400 1909
1032
1273
1510
139
600
628
659
713
832
894
924
934
998
1.0 1250
1272
1447
1641
1645
1678
1780
1782
1871
282
335
359
436
650
739
808
30 1033
1882
1957
1967
158
199
470
605
818
97
1027 1009
1362
1463
1486
1488
1684
1785
116
118
192
234
521
524
731
730
914
47
7
1121 1171
1266
1576
1758
258
261
327
349
362
786
916
69
98 1071
1283
1448
1832
1913
405
510
819
938 1144
1228
1334
1437
1468
1477
1493
1553
1715
1929
1941
127
164
206
218
241
355
390
446
481
609
734
811
837
919
984
996
26
28
1937
492 1205 555 1609
1069
1409
1415
1583
1761
1853
590
842
920 1330
1590
277
513
913
1354 1099
1560
1877
407
461
746
903
908 1087
1164
1461
1657
431
41
Dim2 (15.4%)
0.5 1041
1580
1663
1736
440
552
905
789
1035
1049
1054
1070
1095
1139
1153
1188
1196
1198
1214
1221
1231
1256
1292
1326
1344
1347
1352
1361
1370
1404
1417
1459
1475
1495
1545
1572
1574
1587
1624
1636
1698
1700
1717
1760
1794
1796
1807
1827
1849
1898
1906
1926
1973
1980
141
148
153
173
182
186
189
221
240
253
296
295
311
317
342
454
468
480
483
493
499
561
611
623
634
649
674
684
693
729
735
761
773
779
783
815
825
848
867
883
886
941
953
956
14
21
64
67
82
89
93
95
1107
1131
1165
1178
1185
1268
1337
1389
1395
1431
1507
1552
1555
1561
1579
1585
1617
1643
1671
1694
1742
1791
1797
1824
1854
1880
1892
1943
1968
102
274
350
437
482
515
517
533
538
546
560
613
644
647
701
718
866
912
931
936
946
975
43
61
73 1000
1006
1014
1045
1061
1086
1097
1106
1110
1123
1129
1141
1151
1170
1192
1209
1227
1247
1267
1276
1293
1303
1306
1311
1323
1340
1372
1396
1416
1433
1436
1462
1474
1481
1491
1500
1519
1535
1537
1541
1546
1606
1621
1646
1668
1687
1705
1722
1724
1726
1735
1739
1744
1773
1786
1788
1804
1816
1848
1851
1864
1863
1868
1881
1894
1952
1958
1965
1970
1996
114
117
146
179
178
184
191
195
222
233
247
255
280
305
312
325
324
340
352
381
386
398
403
402
426
432
458
489
502
508
523
527
530
536
540
574
573
577
604
603
625
631
656
655
662
675
682
687
686
716
750
755
765
782
785
802
805
807
814
824
829
844
850
858
865
874
888
895
910
915
917
960
965
968
978
985
999
29
31
40
46
63
72
77
87
90
11 1993
1002
1001
1028
1102
1104
1149
1154
1157
1167
1248
1254
1279
1281
1333
1387
1397
1444
1451
1458
1478
1483
1502
1505
1520
1594
1629
1674
1757
1809
1811
1835
1903
1982
1991
100
163
201
229
250
254
351
389
417
419
424
433
435
442
503
512
528
572
671
676
692
696
700
743
757
799
863
868
872
875
887
897
943
964
994
75
627
851 1022
1090
1115
1120
1138
1237
1270
1325
1406
1476
1512
1566
1577
1608
1613
1662
1713
1753
1858
1873
1934
1945
1947
1951
1964
1977
110
112
142
298
428
462
472
541
547
610
689
694
709
724
756
838
871
12
37
84
0.0 1056
1063
1062
1074
1118
1142
1166
1190
1197
1208
1219
1224
1226
1287
1290
1300
1304
1309
1328
1345
1371
1380
1382
1428
1427
1450
1455
1469
1514
1521
1530
1539
1547
1557
1556
1647
1652
1661
1686
1693
1704
1703
1729
1737
1781
1795
1818
1838
1855
1915
1928
1939
1949
1959
1985
1990
169
168
174
176
183
198
208
211
232
252
263
271
279
291
313
373
409
416
450
455
467
469
484
494
496
504
506
542
576
581
596
598
629
640
648
652
673
672
683
705
704
703
722
748
770
774
831
843
855
862
889
900
899
898
907
982
991
18
17
35
79
85
4
1130
32 1037
1044
1048
1112
1177
1199
1217
1243
1265
1313
1348
1368
1386
1419
1422
1523
1525
1571
1626
1630
1639
1649
1676
1682
1696
1699
1734
1733
1778
1846
1860
1886
1891
1930
1963
104
103
134
140
143
154
187
203
202
239
242
251
372
371
385
414
516
535
559
669
691
695
698
715
792
817
816
823
833
892
909
930
929
51
1883
269
319 1011
1013
1016
1018
1024
1034
1040
1051
1055
1060
1068
1075
1084
1122
1125
1132
1135
1143
1152
1187
1186
1193
1206
1230
1258
1263
1269
1271
1277
1329
1332
1331
1338
1343
1350
1355
1358
1378
1399
1402
1408
1411
1423
1432
1438
1445
1456
1487
1490
1499
1498
1497
1509
1518
1531
1549
1558
1569
1575
1582
1581
1589
1591
1612
1614
1622
1633
1644
1655
1658
1664
1697
1702
1716
1719
1718
1723
1725
1731
1730
1746
1750
1756
1769
1789
1798
1801
1823
1826
1837
1840
1842
1844
1872
1879
1905
1924
1933
1936
1935
1938
1944
1950
1966
1979
106
144
152
155
175
193
207
210
212
217
216
227
226
225
224
223
236
238
249
256
276
275
283
286
285
297
303
315
320
328
369
392
396
400
408
410
429
463
491
501
509
514
519
518
557
582
595
594
593
602
615
636
641
643
654
657
668
702
727
732
736
742
749
751
753
775
793
795
806
813
820
822
826
841
869
918
940
945
949
948
958
976
993
13
27
48
52
56
60
76
99
1
1026
1043
1042
1072
1077
1098
1109
1113
1158
1183
1202
1204
1220
1244
1291
1296
1302
1315
1317
1327
1336
1364
1369
1410
1435
1494
1515
1522
1527
1568
1586
1610
1620
1651
1654
1656
1670
1766
1783
1793
1884
1895
1917
1955
1969
1981
1998
105
121
172
190
194
219
244
268
272
310
347
363
388
474
511
529
531
549
554
569
575
617
621
646
661
690
721
741
760
778
828
856
902
951
954
977
58 1008
1021
1047
1052
1085
1092
1094
1137
1140
1145
1155
1181
1184
1212
1252
1294
1297
1299
1414
1504
1659
1675
1762
1799
1852
1870
1899
1914
1992
1995
149
165
177
306
308
329
336
368
367
412
471
498
534
589
619
632
635
706
882
62 1017
1020
1025
1029
1053
1059
1065
1073
1080
1083
1089
1091
1096
1101
1117
1124
1127
1148
1174
1173
1179
1191
1194
1200
1210
1218
1229
1233
1236
1239
1242
1246
1257
1260
1259
1264
1280
1282
1286
1289
1288
1295
1301
1307
1316
1318
1320
1339
1346
1351
1360
1359
1363
1374
1383
1385
1393
1392
1391
1398
1405
1407
1412
1418
1440
1442
1453
1452
1460
1473
1472
1471
1480
1485
1496
1501
1506
1508
1517
1516
1529
1534
1538
1548
1551
1562
1564
1567
1588
1592
1597
1599
1605
1615
1623
1632
1635
1637
1667
1666
1672
1677
1680
1679
1683
1685
1688
1692
1691
1690
1708
1707
1712
1720
1728
1727
1741
1755
1754
1767
1776
1784
1800
1803
1802
1815
1814
1817
1820
1829
1845
1857
1859
1861
1888
1900
1902
1910
1916
1920
1919
1922
1940
1942
1948
1953
1961
1976
1975
1974
1989
101
108
119
124
126
131
130
129
133
138
150
157
156
159
167
170
181
185
188
200
214
220
235
237
246
248
260
266
265
270
284
288
304
314
316
318
322
331
334
339
338
348
356
364
370
374
391
418
422
421
439
438
443
449
448
457
456
459
464
475
486
485
497
500
507
526
525
537
544
551
550
562
568
567
566
565
564
570
578
580
588
587
586
585
584
592
591
599
601
606
608
614
620
622
624
626
645
651
653
664
666
678
677
680
711
717
720
725
738
737
740
754
764
763
768
767
776
787
790
798
797
796
804
803
812
827
834
836
839
854
857
860
864
870
873
879
878
877
881
890
893
896
901
926
925
932
935
937
942
944
950
952
955
959
972
971
970
974
981
980
979
986
990
992
995
997
19
22
24
39
42
45
50
49
54
53
57
65
78
83
96
5
1225 1563 1897
1896 1834 1665
1023
1031
1030
1081
1133
1160
1195
1223
1241
1245
1253
1285
1308
1312
1321
1324
1335
1365
1390
1421
1434
1464
1526
1532
1565
1593
1598
1619
1625
1640
1653
1681
1740
1743
1759
1775
1839
1850
1862
1878
1956
1972
107
136
162
166
245
293
301
300
365
399
411
430
495
505
545
556
558
658
714
723
728
745
759
762
780
845
884
921
957
961
989
44
3
923 969
1216
1648
1695
1986
1994 383
80 15 1847
1004
1015
1046
1064
1078
1082
1093
1111
1172
1189
1207
1234
1251
1278
1284
1319
1349
1353
1375
1401
1424
1426
1454
1603
1650
1709
1748
1772
1790
1828
1843
1885
1889
1908
1912
1927
1971
128
161
230
259
287
299
321
354
357
361
375
382
387
425
441
460
476
520
579
583
633
637
642
665
667
710
733
752
758
781
791
849
885
904
962
973
71
70
86
1182
1830
1876
1890
2000
34
1136
1528
1751
1771 1012
1039
1103
1105
1116
1134
1156
1163
1203
1235
1240
1249
1274
1305
1342
1377
1379
1413
1429
1443
1533
1536
1540
1544
1559
1570
1616
1634
1642
1689
1738
1747
1765
1770
1792
1805
1822
1867
1887
1921
1923
1931
1954
1978
1983
125
171
180
205
204
215
307
332
376
384
395
394
401
451
466
477
553
607
618
638
660
699
769
809
846
852
861
906
922
947
983
23
25
66
94
1381 1010
1036
1038
1050
1161
1175
1211
1213
1232
1238
1275
1298
1314
1322
1341
1356
1366
1388
1394
1403
1425
1441
1446
1449
1466
1470
1482
1484
1511
1542
1573
1578
1584
1602
1601
1611
1628
1631
1669
1706
1714
1749
1752
1764
1763
1808
1813
1819
1821
1825
1833
1865
1907
1925
1962
1984
1999
111
113
123
122
137
151
196
213
231
257
262
278
289
302
309
346
345
344
397
413
434
444
447
452
478
490
522
543
630
639
663
685
688
712
719
744
772
771
788
794
821
835
847
859
876
891
928
939
988
987
16
36
59
74
91
9
1960
135
333
147
880 1007
1019
1058
1057
1079
1088
1100
1108
1126
1128
1162
1168
1180
1201
1222
1255
1262
1261
1310
1357
1367
1373
1376
1384
1430
1439
1457
1465
1467
1492
1524
1550
1554
1596
1595
1600
1607
1618
1627
1638
1660
1701
1721
1768
1774
1787
1812
1831
1875
1874
1911
1946
1988
81 1005
1869 115
132
145
197
209
243
264
273
292
294
337
341
358
360
380
379
378
377
404
415
427
445
453
465
473
539
612
616
670
679
681
707
726
747
766
810
840
927
963
967
10
20
38
55
92
2
6
1119
1710
−0.5
1777
109
330
488 933
1150
1673
1856
1932
acm1_ad |>
factoextra::fviz_mca_ind(
geom.ind = "point",
alpha.ind = 0.1
)
657
Individuals − MCA
1.0
Dim2 (15.4%)
0.5
0.0
−0.5
acm1_ad |>
factoextra::fviz_mca_ind(
habillage = d$sport,
addEllipses = TRUE,
geom.ind = "point",
alpha.ind = 0.1
)
658
Individuals − MCA
1.0
0.5
Dim2 (15.4%)
Groups
Non
0.0
Oui
−0.5
−1.0
Ď Astuce
acm1_ad |>
ade4::scatter(col = khroma::colour("bright")(2))
659
hard.rock lecture.bd peche.chasse
Oui
Non Non
Oui Non
Oui
Oui Non
OuiNon
Non Oui
sport
Non
Oui
660
as_tibble(res$coord)
# A tibble: 2,000 x 7
Dim.1 Dim.2 Dim.3 Dim.4 Dim.5 Dim.6 Dim.7
<dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
1 0.380 -0.0481 -0.130 -0.0757 -0.554 -0.118 -0.0382
2 -0.301 -0.512 0.0125 0.221 0.421 -0.340 -0.0402
3 0.146 -0.261 0.0784 0.152 0.279 -0.252 -0.578
4 -0.842 -0.0612 0.00886 0.247 -0.232 0.149 -0.0297
5 0.614 -0.149 0.0190 -0.0259 0.139 -0.0253 -0.0474
6 -0.301 -0.512 0.0125 0.221 0.421 -0.340 -0.0402
7 0.270 0.905 -0.214 -0.198 -0.267 -0.732 0.144
8 -0.0369 1.26 -0.0688 -0.122 -0.227 -0.150 0.146
9 0.167 -0.400 -0.0469 0.0425 0.282 -0.114 0.490
10 -0.301 -0.512 0.0125 0.221 0.421 -0.340 -0.0402
# i 1,990 more rows
661
)
)
662
acm1_ad,
acm_add$tab
)
acm2_fm |>
factoextra::fviz_mca_var(repel = TRUE, labelsize = 2)
2
Dim2 (15.4%)
663
39.4 Gestion des valeurs manquantes
664
ACM3 avec ade4 ACM3 avec FactoMineR
0.3 0.3
0.2 0.2
Eigenvalue
Eigenvalue
0.1 0.1
0.0 0.0
1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10
Dimensions Dimensions
d3 |> questionr::freq.na()
missing %
nivetud 112 6
sexe 0 0
groupe_ages 0 0
hard.rock 0 0
lecture.bd 0 0
peche.chasse 0 0
cuisine 0 0
bricol 0 0
cinema 0 0
sport 0 0
665
Pour éviter toute ambiguïté, il est préférable de traiter soi-
même les valeurs manquantes (NA) en amont des deux fonc-
tions.
Pour convertir les valeurs manquantes d’un facteur en une mo-
dalité en soi, on utilisera forcats::fct_na_value_to_level().
Il est possible d’appliquer cette fonction à tous les facteurs d’un
tableau de données avec dplyr::across() (cf. Chapitre 38).
# Previously
across(a:b, mean, na.rm = TRUE)
# Now
across(a:b, \(x) mean(x, na.rm = TRUE))
[1] 2000
666
missing %
sexe 0 0
groupe_ages 0 0
nivetud 0 0
hard.rock 0 0
lecture.bd 0 0
peche.chasse 0 0
cuisine 0 0
bricol 0 0
cinema 0 0
sport 0 0
[1] 1888
missing %
sexe 0 0
groupe_ages 0 0
nivetud 0 0
hard.rock 0 0
lecture.bd 0 0
peche.chasse 0 0
cuisine 0 0
bricol 0 0
cinema 0 0
sport 0 0
667
en conservant l’ensemble des individus. Les valeurs manquantes
sont automatiquement considérées comme des modalités à ne
pas tenir compte. Mais il est également possible d’indiquer
d’autres modalités à ignorer (voir le tutoriel du package).
39.5 webin-R
668
40 Classification ascendante
hiérarchique
𝑝
1
𝑆𝑔 (𝑥1 , 𝑥2 ) = ∑ 𝑠12𝑗
𝑝 𝑗=1
Sur les 5 variables utilisées pour les décrire, 1 et 2 ont deux ca-
ractéristiques communes : ils sont grand(e)s et étudiant(e)s. Dès
lors, l’indice de similarité de Gower entre 1 et 2 vaut 2/5 = 0,4
(soit une distance de 1 − 0,4 = 0,6).
Plusieurs approches peuvent être retenues pour traiter les va-
leurs manquantes :
671
Si l’on supprime les individus ayant des valeurs manquantes,
2 est retirée du fichier d’observations et aucune distance n’est
calculée.
Si l’on traite les valeurs manquantes comme une modalité
particulière, 1 et 2 partagent alors 2 caractères sur les
5 analysés, la distance de Gower entre eux est alors de
1 − 2/5 =1 − 0,4 = 0,6.
Si on garde les valeurs manquantes, l’indice de Gower est
dès lors calculé sur les seuls descripteurs renseignés à la fois
pour 1 et 2. La distance de Gower sera calculée dans le cas
présent uniquement sur les 4 caractères renseignés et vaudra
1 − 2/4 = 0,5.
40.1.2 Distance du Φ²
2 1 (𝛿𝑖𝑘 − 𝛿𝑗𝑘 )2
𝑑Φ 2 (𝐿𝑖 , 𝐿𝑗 ) = ∑
𝑄 𝑘 𝑓𝑘
672
2. femme / grande / brune / étudiante / rurale
• hommes : 52 % / femmes : 48 %
• grand : 30 % / moyen : 45 % / petit : 25 %
• blond : 15 % / châtain : 45 % / brun : 30 % / blanc :
10 %
• étudiant : 20 % / salariés : 65 % / retraités : 15 %
• urbain : 80 % / rural : 20 %
2 1 1 1 1 1 1 1
𝑑Φ 2 (𝐿1 , 𝐿2 ) = ( + + + + + ) = 4, 05
5 0, 52 0, 48 0, 15 0, 30 0, 80 0, 20
40.1.3 Illustration
library(tidyverse)
data("hdv2003", package = "questionr")
673
d <- hdv2003 |>
select(hard.rock:sport)
Ď Astuce
674
Cependant, à l’usage, on privilégiera le plus souvent la méthode
de Ward64 . De manière simplifiée, cette méthode cherche à mini- 64
Ward, J. (1963). Hierarchical
miser l’inertie intra-classe et à maximiser l’inertie inter-classe Grouping to Optimize an Objective
Function. Journal of the American
afin d’obtenir des classes les plus homogènes possibles. Cette
Statistical Association, 58(301), 236-
méthode est souvent incorrectement présentée comme une mé- 244. doi:10.2307/2282967. (h t tp : / /
thode de minimisation de la variance alors qu’au sens strict www.jstor.org/stable/2282967)
Ward vise l’augmentation minimum de la somme des carrés
(“minimum increase of sum-of-squares (of errors)”)65 . 65
Voir par exemple la discussion, en
anglais, sur Wikipedia concernant la
En raison de la variété des distances possibles et de la variété page présentant la méthode Ward : ht
des techniques d’agrégation, on pourra être amené à réaliser tps://en.wikipedia.org/wiki/Talk:
plusieurs dendrogrammes différents sur un même jeu de don- Ward%27s_method
nées jusqu’à obtenir une classification qui fait « sens ».
La fonction de base pour le calcul d’un dendrogramme est
stats::hclust() en précisant le critère d’agrégation avec
method. Dans notre cas, nous allons opter pour la méthode de
Ward appliquée au carré des distances (ce qu’on indique avec
method = "ward.D2"66 ) : 66
L’option method = "ward.D" cor-
respondant à la méthode de Ward
sur la matrice des distances simples
arbre_phi2 <- md_phi2 |>
(i.e. sans la passer au carré). Mais il
hclust(method = "ward.D2") est à noter que la méthode décrite par
Ward dans son article de 1963 corres-
pond bien à method = "ward.D2".
Ď Astuce
675
Ĺ Note
arbre_gower |>
plot(labels = FALSE, main = "Dendrogramme (distance de Gower)")
676
Dendrogramme (distance de Gower)
8
6
Height
4
2
0
md_gower
fastcluster::hclust (*, "ward.D2")
arbre_gower |>
factoextra::fviz_dend(show_labels = FALSE) +
ggplot2::ggtitle("Dendrogramme (distance de Gower)")
677
Dendrogramme (distance de Gower)
7.5
5.0
Height
2.5
0.0
678
ensuite en deux branches bien visibles, suggérant une possible
classification en 4 groupes.
Nous pouvons l’impact d’un découpage avec factoextra::fviz_dend()
en précisant k = 4 pour lui indiquer de colorer un découpage
en 4 classes. On peut optionnellement ajouter rect = TRUE
pour dessiner des rectangles autour de chaque classe.
arbre_gower |>
factoextra::fviz_dend(
show_labels = FALSE,
k = 4,
rect = TRUE
) +
ggplot2::ggtitle("Dendrogramme découpé en 4 classes (distance de Gowver)")
7.5
5.0
Height
2.5
0.0
679
la perte relative (i.e. la perte absolue exprimée en pourcentage
de la hauteur précédente). {FactoMineR} (que nous aborderons
un peu plus loin) suggère par défaut la partition correspondant
à la plus grande perte relative d’inertie (the one with the higher
relative loss of inertia).
Pour faciliter les choses, voici deux petites fonctions
que vous pouvez recopier / adapter dans vos scripts.
get_inertia_from_tree() calcule l’inertie à chaque niveau,
ainsi que les pertes absolues et relatives. plot_inertia_from_tree()
en propose une représentation graphique.
680
ggplot2::ylab("Absolute loss")
p_relative <-
ggplot2::ggplot(d) +
ggplot2::aes(x = k, y = relative_loss) +
ggplot2::geom_line(color = "#AA3377") +
ggplot2::geom_point(size = 3, color = "#AA3377") +
ggplot2::scale_y_continuous(label = scales::percent) +
ggplot2::ylab("Relative loss")
patchwork::wrap_plots(
p_inertia,
p_absolute,
p_relative,
ncol = 1
) &
ggplot2::theme_light() &
ggplot2::xlab("Number of clusters") &
ggplot2::scale_x_continuous(
breaks = d$k,
minor_breaks = NULL,
limits = c(1, k_max)
)
}
arbre_gower |>
plot_inertia_from_tree()
681
7.5
Inertia
5.0
2.5
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
0
Absolute loss
−1
−2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
0%
Relative loss
−10%
−20%
−30%
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
682
gramme, en indiquant le nombre de classes souhaitées67 . 67
Ici, nous pouvons ajouter le ré-
sultat obtenu directement à notre ta-
bleau de données hdv2003 dans la me-
hdv2003$typo_gower_4classes <- arbre_gower |>
sure où, depuis le début de l’analyse,
cutree(4) l’ordre des lignes n’a jamais changé à
aucune étape de l’analyse.
Nous pouvons rapidement faire un tri à plat avec gtsummary::tbl_summary().
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",")
hdv2003 |>
tbl_summary(include = typo_gower_4classes)
Caractéristique N = 2 000
typo_gower_4classes
1 837 (42%)
2 636 (32%)
3 172 (8,6%)
4 355 (18%)
683
arbre_phi2 |>
factoextra::fviz_dend(show_labels = FALSE) +
ggplot2::ggtitle("Dendrogramme (distance du Phi²)")
20
15
Height
10
Ĺ Note
684
ce que l’on souhaite faire émerger.
arbre_phi2 |>
plot_inertia_from_tree()
25
20
Inertia
15
10
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
−2
Absolute loss
−4
−6
−8
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
0%
Relative loss
−10%
−20%
−30%
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
685
hdv2003$typo_phi2_5classes <- arbre_phi2 |>
cutree(5)
hdv2003 |>
tbl_summary(include = typo_phi2_5classes)
Caractéristique N = 2 000
typo_phi2_5classes
1 1 010 (51%)
2 713 (36%)
3 216 (11%)
4 14 (0,7%)
5 47 (2,4%)
acm_ad |>
factoextra::fviz_mca_ind(
habillage = hdv2003$typo_phi2_5classes,
addEllipses = TRUE,
geom.ind = "point",
alpha.ind = 0.1
)
686
Individuals − MCA
1.5
1.0
Groups
Dim2 (15.4%)
0.5 1
2
0.0 3
4
−0.5
5
−1.0
−2 −1 0 1
Dim1 (21.2%)
Ĺ Note
687
PBC ( 0.27 / 0.51 )
HG ( 0.42 / 0.97 )
0.8
R2 ( 0.12 / 0.9 )
R2sq ( 0.15 / 0.94 )
HC ( 0 / 0.29 )
0.0
5 10 15 20
N clusters
688
Nous pouvons directement passer le résultat de FactoMineR::HCPC()
à factoextra::fviz_dend() pour visualiser le dendrogramme,
qui sera d’ailleurs automatiquement colorié à partir de la par-
tition recommandée par FactoMineR::HCPC().
cah_fm |>
factoextra::fviz_dend(show_labels = FALSE)
Cluster Dendrogram
0.15
0.10
Height
0.05
0.00
cah_fm |>
plot_inertia_from_tree()
689
0.15
0.10
Inertia
0.05
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
0.00
Absolute loss
−0.02
−0.04
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
0%
Relative loss
−20%
−40%
−60%
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Number of clusters
690
de couvrir au moins 80 à 90 % de la variance.
De son côté, ade4::dist.dudi() prends en compte l’ensemble
des axes pour calculer la matrice des distances. On peut repro-
duire cela avec {FactoMineR} en indiquant ncp = Inf lors du
calcul de l’ACM.
cah_fm2 |>
factoextra::fviz_dend(show_labels = FALSE)
Cluster Dendrogram
0.15
0.10
Height
0.05
0.00
cah_fm2 |>
plot()
691
Hierarchical clustering on the factor map
cluster 1
cluster 2
cluster 3
Dim 2 (15.43%)
0.000.050.100.150.20
cluster 4
cluster 5
height
1.5
1.0
88 1066
1076
1918
1732
1711
1543
1513
1479
1420
1176
1169
1159
801
777
697
571
563
548
532
423
406
366
343
290
228
120
68
33 1997
1904
1901
1841
1836
1806
1779
1745
1604
1489
1215
1147
1146
1114
1067
966
911
853
830
800
708
597
487
353
267
160
81032
1909
1893
1510
1273 1987
1866
1810
1503
1003
9981400
934
924
894
832
713
659
628
600
139 281784 1250
479
420
393
326
323 0.5
28 1009
1941
1929
1715
1553
1493
1477
1468
1437
1334
1228
1144
996
984
919
837
811
734
609
481
446
390
355
241
218
206
164
127
26 1785
1684
1488
1486
1463
1362
914
731
730
524
521
234
192
118
116
47
71330
1609
1590 1967
1957
1882
1033
818
605
470
199
158
1913
1832
1448
1283
1071
9131069
513
2771853
1761
1583
1415
1409
920
842
590
555938
819
510
40597
1027 98 1272
1758
1576
1266
1171
916
786
362
349
327
261
258
120569 1871
1782
1780
1678
1645
1641
1447
808
739
650
436
359
335
282
30 1121
0.0
1657
1461
1164
1087
431
41 905 1099
1877
1560
903
746
461
407
908 1354 1937
492
1979
1966
1950
1944
1938
1936
1935
1933
1924
1905
1879
1872
1844
1842
1840
1837
1826
1823
1801
1798
1789
1769
1756
1750
1746
1731
1730
1725
1723
1719
1718
1716
1702
1697
1664
1658
1655
1644
1633
1622
1614
1612
1591
1589
1582
1581
1575
1569
1558
1549
1531
1518
1509
1499
1498
1497
1490
1487
1456
1445
1438
1432
1423
1411
1408
1402
1399
1378
1358
1355
1350
1343
1338
1332
1331
1329
1277
1271
1269
1263
1258
1230
1206
1193
1187
1186
1152
1143
1135
1132
1125
1122
1084
1075
1068
1060
1055
1051
1040
1034
1024
1018
1016
1013
1011
993
976
958
949
948
945
940
918
869
841
826
822
820
813
806
795
793
775
753
751
749
742
736
732
727
702
668
657
654
643
641
636
615
602
595
594
593
582
557
519
518
514
509
501
491
463
429
410
408
400
396
392
369
328
320
315
303
297
286
285
283
276
275
256
249
238
236
227
226
225
224
223
217
216
212
210
207
193
175
155
152
144
106
13
99
76
60
56
52
48
27
1 90 1035
1996
1970
1965
1958
1952
1894
1881
1868
1864
1863
1851
1848
1816
1804
1788
1786
1773
1744
1739
1735
1726
1724
1722
1705
1687
1668
1646
1621
1606
1546
1541
1537
1535
1519
1500
1491
1481
1474
1462
1436
1433
1416
1396
1372
1340
1323
1311
1306
1303
1293
1276
1267
1247
1227
1209
1192
1170
1151
1141
1129
1123
1110
1106
1097
1086
1061
1045
1014
1006
1000
999
985
978
968
965
960
917
915
910
895
888
874
865
858
850
844
829
824
814
807
805
802
785
782
765
755
750
716
687
686
682
675
662
656
655
631
625
604
603
577
574
573
540
536
530
527
523
508
502
489
458
432
426
403
402
398
386
381
352
340
325
324
312
305
280
255
247
233
222
195
191
184
179
178
146
117
114
87
77
72
63
46
40
31
29 1980
1973
1926
1906
1898
1849
1827
1807
1796
1794
1760
1717
1700
1698
1636
1624
1587
1574
1572
1545
1495
1475
1459
1417
1404
1370
1361
1352
1347
1344
1326
1292
1256
1231
1221
1214
1198
1196
1188
1153
1139
1095
1070
1054
1049
956
953
941
886
883
867
848
825
815
783
779
773
761
735
729
693
684
674
649
634
623
611
561
499
493
483
480
468
454
342
317
311
296
295
253
240
221
189
186
182
173
153
148
141
95
93
89
82
67
64
21
14
1993
1977
1964
1951
1947
1945
1934
1873
1858
1753
1713
1662
1613
1608
1577
1566
1512
1476
1406
1325
1270
1237
1138
1120
1115
1090
1022
871
838
756
724
709
694
689
610
547
541
472
462
428
298
142
112
110
1963
1930
1891
1886
1860
1846
1778
1734
1733
1699
1696
1682
1676
1649
1639
1630
1626
1571
1525
1523
1422
1419
1386
1368
1348
1313
1265
1243
1217
1199
1177
1112
1048
1044
1037
930
929
909
892
833
823
817
816
792
715
698
695
691
669
559
535
516
414
385
372
371
251
242
239
203
202
187
154
143
140
134
104
103
5184
37
12 692
676
671
572
528
512
503
442
435
433
424
419
417
389
351
254
250
229
201
163
100
75
11
851
627731041
1968
1943
1892
1880
1854
1824
1797
1791
1742
1694
1671
1643
1617
1585
1579
1561
1555
1552
1507
1431
1395
1389
1337
1268
1185
1178
1165
1131
1107
975
946
936
931
912
866
718
701
647
644
613
560
546
538
533
517
515
482
437
350
274
102
1991
1982
1903
1835
1811
1809
1757
1674
1629
1594
1520
1505
1502
1483
1478
1458
1451
1444
1397
1387
1333
1281
1279
1254
1248
1167
1157
1154
1149
1104
1102
1028
1002
1001
994
964
943
897
887
875
872
868
863
799
757
743
700
69661
431736
1663
1580
552
440
789
1990
1985
1959
1949
1939
1928
1915
1855
1838
1818
1795
1781
1737
1729
1704
1703
1693
1686
1661
1652
1647
1557
1556
1547
1539
1530
1521
1514
1469
1455
1450
1428
1427
1382
1380
1371
1345
1328
1309
1304
1300
1290
1287
1226
1224
1219
1208
1197
1190
1166
1142
1118
1074
1063
1062
1056
991
982
907
900
899
898
889
862
855
843
831
774
770
748
722
705
704
703
683
673
672
652
648
640
629
598
596
581
576
542
506
504
496
494
484
469
467
455
450
416
409
373
313
291
279
271
263
252
232
211
208
198
183
176
174
169
168
85
79
35
18
17
4 −0.5
1989
1976
1975
1974
1961
1953
1948
1942
1940
1922
1920
1919
1916
1910
1902
1900
1888
1861
1859
1857
1845
1829
1820
1817
1815
1814
1803
1802
1800
1784
1776
1767
1755
1754
1741
1728
1727
1720
1712
1708
1707
1692
1691
1690
1688
1685
1683
1680
1679
1677
1672
1667
1666
1637
1635
1632
1623
1615
1605
1599
1597
1592
1588
1567
1564
1562
1551
1548
1538
1534
1529
1517
1516
1508
1506
1501
1496
1485
1480
1473
1472
1471
1460
1453
1452
1442
1440
1418
1412
1407
1405
1398
1393
1392
1391
1385
1383
1374
1363
1360
1359
1351
1346
1339
1320
1318
1316
1307
1301
1295
1289
1288
1286
1282
1280
1264
1260
1259
1257
1246
1242
1239
1236
1233
1229
1218
1210
1200
1194
1191
1179
1174
1173
1148
1127
1124
1117
1101
1096
1091
1089
1083
1080
1073
1065
1059
1053
1029
1025
1020
1017
997
995
992
990
986
981
980
979
974
972
971
970
959
955
952
950
944
942
937
935
932
926
925
901
896
893
890
881
879
878
877
873
870
864
860
857
854
839
836
834
827
812
804
803
798
797
796
790
787
776
768
767
764
763
754
740
738
737
725
720
717
711
680
678
677
666
664
653
651
645
626
624
622
620
614
608
606
601
599
592
591
588
587
586
585
584
580
578
570
568
567
566
565
564
562
551
550
544
537
526
525
507
500
497
486
485
475
464
459
457
456
449
448
443
439
438
422
421
418
391
374
370
364
356
348
339
338
334
331
322
318
316
314
304
288
284
270
266
265
260
248
246
237
235
220
214
200
188
185
181
170
167
159
157
156
150
138
133
131
130
129
126
124
119
108
101
96
83
78
65
57
54
53
50
49
45
42
39
24
22
19
5 1010
1972
1956
1878
1862
1850
1839
1775
1759
1743
1740
1681
1653
1640
1625
1619
1598
1593
1565
1532
1526
1464
1434
1421
1390
1365
1335
1324
1321
1312
1308
1285
1253
1245
1241
1223
1195
1160
1133
1081
1031
1030
1023 1883
1995
1992
1914
1899
1870
1852
1799
1762
1675
1659
1504
1414
1299
1297
1294
1252
1212
1184
1181
1155
1145
1140
1137
1094
1092
1085
1052
1047
1021
1008
882
706
635
632
619
589
534
498
471
412
368
367
336
329
308
306
177
165
149319
269
62 1012
1665 1998
1981
1969
1955
1917
1895
1884
1793
1783
1766
1670
1656
1654
1651
1620
1610
1586
1568
1527
1522
1515
1494
1435
1410
1369
1364
1336
1327
1317
1315
1302
1296
1291
1244
1220
1204
1202
1183
1158
1113
1109
1098
1077
1072
1043
1042
1026
977
954
951
902
856
828
778
760
741
721
690
661
646
621
617
575
569
554
549
531
529
511
474
388
363
347
310
272
268
244
219
194
190
172
121
105 1130
581563
1897
18341896329691216
1225
9107
1999
1984
1962
1925
1907
1865
1833
1825
1821
1819
1813
1808
1764
1763
1752
1749
1714
1706
1669
1631
1628
1611
1602
1601
1584
1578
1573
1542
1511
1484
1482
1470
1466
1449
1446
1441
1425
1403
1394
1388
1366
1356
1341
1322
1314
1298
1275
1238
1232
1213
1211
1175
1161
1050
1038
1036
988
987
939
928
891
876
859
847
835
821
794
788
772
771
744
719
712
688
685
663
639
630
543
522
490
478
452
447
444
434
413
397
346
345
344
309
302
289
278
262
257
231
213
196
151
137
123
122
113
111
91
74
59
36
16
1960
333
135989
961
957
921
884
845
780
762
759
745
728
723
714
658
558
556
545
505
495
430
411
399
365
301
300
293
245
166
162
136
44
3 1182
1847 1971
1927
1912
1908
1889
1885
1843
1828
1790
1772
1748
1709
1650
1603
1454
1426
1424
1401
1375
1353
1349
1319
1284
1278
1251
1234
1207
1189
1172
1111
1093
1082
1078
1064
1046
1015
1004
973
962
904
885
849
791
781
758
752
733
710
667
665
642
637
633
583
579
520
476
460
441
425
387
382
375
361
357
354
321
299
287
259
230
161
128
86
71
70
15
2000
1890
1876
1830
341988
1946
1911
1875
1874
1831
1812
1787
1774
1768
1721
1701
1660
1638
1627
1618
1607
1600
1596
1595
1554
1550
1524
1492
1467
1465
1457
1439
1430
1384
1376
1373
1367
1357
1310
1262
1261
1255
1222
1201
1180
1168
1162
1128
1126
1108
1100
1088
1079
1058
1057
1019
1007
967
963
927
840
810
766
747
726
707
681
679
670
616
612
539
473
465
453
445
427
415
404
380
379
378
377
360
358
341
337
294
292
273
264
243
209
197
145
132
115
92
55
38
20
10 383
1983
1978
1954
1931
1923
1921
1887
1867
1822
1805
1792
1770
1765
1747
1738
1689
1642
1634
1616
1570
1559
1544
1540
1536
1533
1443
1429
1413
1379
1377
1342
1305
1274
1249
1240
1235
1203
1163
1156
1134
1116
1105
1103
1039
983
947
922
906
861
852
846
809
769
699
660
638
618
607
553
477
466
451
401
395
394
384
376
332
307
215
205
204
180
171
125
94
66
25
23 80
1381 1777
6 1869
2
1005
1710
1119 81 1771
1751
1528
1136
880
147 1994
1986
1695
1648
923−1.0
−1.0 −0.5 0.0 933
0.5 1932
1856
1673
11501.0109
488
330 1.5
Dim 1 (21.22%)
cah_fm2 |>
plot(choice = "tree")
692
Height
1871
1782
1780
1678
1645
1641
1447
1272
1250
808
739
650
436
359
335
30
282
1758
cutree(3)
1576
1266
1171
916
786
362
349
327
261
258
69
98
1967
1957
1882
1033
818
605
470
199
97
158
281
1400
1909
1893
1510
1273
1032
998
934
924
894
832
713
659
628
139
600
1987
1866
1810
1503
1003
784
479
420
393
323
326
1609
1590
1330
913
277
513
1736
1663
1580
1041
905
440
552
1913
1832
1448
1283
1071
938
819
405
510
1877
1560
1099
903
746
407
461
1918
1732
1711
1543
1513
1479
1420
1176
1169
1159
1076
801
777
697
571
563
548
532
423
406
366
343
290
228
120
88
33
68
8
1997
1904
1901
1841
1836
1806
1779
1745
1604
1489
1215
1147
1146
1114
1067
1066
966
911
853
830
800
708
597
487
353
160
267
1941
1929
1715
1553
1493
1477
1468
1437
1334
1228
1144
996
984
919
837
811
734
609
481
446
390
355
241
218
206
164
127
26
28
7
1785
1684
1488
1486
1463
1362
1009
914
731
730
524
521
234
192
118
47
116
1657
1461
1164
1087
41
431
1853
1761
1583
1415
1409
1069
920
842
555
590
1979
1966
1950
1944
1938
1936
1935
1933
1924
1905
1879
1872
1844
1842
1840
1837
1826
1823
1801
1798
1789
1769
1756
1750
1746
1731
1730
1725
1723
1719
1718
1716
1702
1697
1664
1658
1655
1644
1633
1622
1614
FactoMineR::HCPC().
1597
1592
1588
1567
1564
1562
1551
1548
1538
1534
1529
1517
1516
1508
1506
1501
1496
1485
1480
1473
1472
1471
1460
1453
1452
1442
1440
1418
1412
1407
1405
1398
1393
1392
1391
1385
1383
1374
1363
1360
1359
1351
1346
1339
1320
1318
1316
1307
1301
1295
1289
1288
1286
1282
1280
1264
1260
1259
1257
1246
1242
1239
1236
1233
1229
1218
1210
1200
1194
1191
1179
1174
1173
1148
1127
1124
1117
1101
1096
1091
1089
1083
1080
1073
1065
1059
1053
1029
1025
1020
1017
997
995
992
990
986
981
980
979
974
972
971
970
959
955
952
950
944
942
937
935
932
926
925
901
896
893
890
881
879
878
877
873
870
864
860
857
854
839
836
834
827
812
804
803
798
797
796
790
787
776
768
767
764
763
754
740
738
737
725
720
717
711
680
678
677
666
664
653
651
645
626
624
622
620
614
608
606
601
599
592
591
588
587
586
585
584
580
578
570
568
567
566
565
564
562
551
550
544
537
526
525
507
500
497
486
485
475
464
459
457
456
449
448
443
439
438
422
421
418
391
374
370
364
356
348
339
338
334
331
322
318
316
314
304
288
284
270
266
265
260
248
246
237
235
220
214
200
188
185
181
170
167
159
157
156
150
138
133
131
130
129
126
124
119
108
101
96
83
78
65
57
54
53
50
49
45
42
39
24
19
22
1968
1943
1892
1880
1854
1824
1797
1791
1742
1694
1671
1643
1617
1585
1579
1561
1555
1552
1507
1431
1395
1389
1337
1268
1185
1178
1165
1131
1107
975
946
936
931
912
866
718
701
647
644
613
560
546
538
533
517
515
482
437
350
274
102
73
43
61
12
1993
1977
1964
1951
1947
1945
1934
1873
1858
1753
1713
1662
1613
1608
1577
1566
1512
1476
1406
1325
1270
1237
1138
1120
1115
1090
1022
871
838
756
724
709
694
689
610
547
541
472
462
428
298
142
112
110
37
84
1995
1992
1914
1899
1870
1852
1799
1762
1675
1659
1504
1414
1299
1297
1294
1252
1212
1184
1181
1155
1145
1140
1137
1094
1092
1085
1052
1047
1021
1008
882
706
635
632
619
589
534
498
471
412
368
367
336
329
308
306
177
165
62
149
3
1972
1956
1878
1862
1850
1839
1775
1759
1743
1740
1681
1653
1640
1625
1619
1598
1593
1565
1532
1526
1464
1434
1421
1390
1365
1335
1324
1321
1312
1308
1285
1253
1245
1241
1223
1195
1160
1133
1081
1031
1030
1023
989
961
957
921
884
845
780
762
759
745
728
723
714
658
558
556
545
505
495
430
411
399
365
301
300
293
245
166
162
136
44
107
1996
1970
1965
1958
1952
1894
1881
1868
1864
1863
1851
1848
1816
1804
1788
1786
1773
1744
1739
1735
1726
1724
1722
1705
1687
1668
1646
1621
1606
1546
1541
1537
1535
1519
1500
1491
1481
1474
1462
1436
1433
1416
1396
1372
1340
1323
1311
1306
1303
1293
1276
1267
1247
1227
1209
1192
1170
1151
1141
1129
1123
1110
1106
1097
1086
1061
1045
1014
1006
1000
999
985
978
968
965
960
917
915
910
895
888
874
865
858
850
844
829
824
814
807
805
802
785
782
765
755
750
716
687
686
682
675
662
656
655
631
625
604
603
577
574
573
540
536
530
527
523
508
502
489
458
432
426
403
402
398
386
381
352
340
325
324
312
305
280
255
247
233
222
195
191
184
179
178
146
117
114
90
87
77
72
63
46
40
29
31
1980
1973
1926
1906
1898
1849
1827
1807
1796
1794
1760
1717
1700
1698
1636
1624
1587
1574
1572
1545
1495
1475
1459
1417
1404
1370
1361
1352
1347
1344
1326
1292
1256
1231
1221
1214
1198
1196
1188
1153
1139
1095
1070
1054
1049
1035
956
953
941
886
883
867
848
825
815
783
779
773
761
735
729
693
cah_fm2$call$t$tree |>
684
674
649
634
623
611
561
499
493
483
480
468
454
342
317
311
296
295
253
240
221
189
186
182
173
153
148
141
95
93
89
82
67
64
14
21
1121
789
908
1847
1665
1381
1119
1710
32
1130
147
880
969
1225
933
81
1869
80
383
1563
1896
1883
269
319
627
851
1960
135
333
2000
1890
1876
1830
34
1182
1027
1205
1354
492
1937
1932
1856
1150
1673
1777
488
109
330
693
1994
1986
1695
1648
923
1216
1771
1751
1136
1528
1005
1834
1897
9
1999
1984
1962
1925
1907
1865
1833
1825
1821
1819
1813
1808
1764
1763
1752
1749
1714
1706
1669
1631
1628
1611
1602
1601
1584
1578
1573
1542
1511
1484
1482
1470
1466
1449
1446
1441
1425
1403
1394
1388
1366
1356
1341
1322
1314
1298
1275
1238
1232
1213
1211
1175
1161
1050
1038
1036
1010
988
987
939
928
891
876
859
847
835
821
794
788
772
771
744
719
712
688
685
663
639
630
543
522
490
478
452
447
444
434
413
397
346
345
344
309
302
289
278
262
257
231
213
196
151
137
123
122
113
111
91
74
59
16
36
1963
1930
1891
1886
1860
1846
1778
1734
1733
1699
1696
1682
1676
1649
1639
1630
1626
1571
1525
1523
1422
1419
1386
1368
1348
1313
1265
1243
1217
1199
1177
1112
1048
1044
1037
930
929
909
892
833
823
817
816
792
715
698
695
691
669
559
535
516
414
385
372
371
251
242
239
203
hdv2003$typo_alternative <-
202
187
154
143
140
134
104
51
103
11
1991
1982
1903
1835
1811
1809
1757
1674
1629
1594
1520
1505
1502
1483
1478
1458
1451
1444
1397
1387
1333
1281
1279
1254
1248
1167
1157
1154
1149
1104
1102
1028
1002
1001
994
964
943
897
887
875
872
868
863
799
757
743
700
696
692
676
671
572
528
512
503
442
435
433
424
419
417
Cluster Dendrogram
389
351
254
250
229
201
163
75
100
1998
1981
1969
1955
1917
1895
1884
1793
1783
1766
1670
1656
1654
1651
1620
1610
1586
1568
1527
1522
1515
1494
1435
1410
1369
1364
1336
1327
1317
1315
1302
1296
1291
1244
1220
1204
1202
1183
1158
1113
1109
1098
1077
1072
1043
1042
1026
977
954
951
902
856
828
778
760
741
721
690
661
646
621
617
575
569
554
549
531
529
511
474
388
363
347
310
272
268
244
219
194
190
172
121
58
105
2
10
6
1988
1946
1911
1875
1874
1831
1812
1787
1774
1768
1721
1701
1660
1638
1627
1618
1607
1600
1596
1595
1554
1550
1524
1492
1467
1465
1457
1439
1430
1384
1376
1373
1367
1357
1310
1262
1261
1255
1222
1201
1180
1168
1162
1128
1126
1108
1100
1088
1079
1058
1057
1019
1007
967
963
927
840
810
766
747
726
707
681
679
670
616
612
539
473
465
453
445
427
415
404
380
379
378
377
360
358
341
337
294
292
273
264
243
209
197
145
132
115
92
55
20
38
4
1990
1985
1959
1949
1939
1928
1915
1855
1838
1818
1795
1781
1737
1729
1704
1703
1693
1686
1661
1652
1647
1557
1556
1547
1539
1530
1521
1514
1469
1455
1450
1428
1427
1382
1380
1371
1345
1328
1309
1304
1300
1290
1287
1226
1224
1219
1208
1197
1190
1166
1142
1118
1074
1063
1062
1056
991
982
907
900
899
898
889
862
855
843
831
774
770
748
722
705
704
703
683
673
672
652
648
640
629
598
596
581
576
542
506
504
496
494
484
469
467
455
450
416
409
373
313
291
279
271
263
252
232
211
208
198
183
176
174
169
168
85
79
35
17
18
1971
1927
1912
1908
1889
1885
1843
1828
1790
1772
1748
1709
1650
1603
1454
1426
1424
667
665
642
637
633
583
579
520
476
460
441
425
387
382
375
361
357
354
321
299
287
259
230
161
128
86
71
15
70
1983
1978
1954
1931
1923
1921
1887
1867
1822
1805
1792
1770
1765
1747
1738
1689
1642
1634
1616
1570
1559
1544
1540
1536
1533
1443
1429
1413
1379
1377
1342
1305
1274
1249
1240
1235
1203
1163
1156
1134
1116
1105
1103
1039
1012
983
947
922
906
861
852
846
809
769
699
660
638
618
607
553
477
466
451
401
395
394
384
376
332
307
215
205
204
180
171
125
94
66
23
25
0.00 0.10
hdv2003 |>
tbl_summary(
include = hard.rock:sport,
by = typo_gower_4classes
) |>
bold_labels()
1, N = 2, N = 3, N = 4, N =
Caractéristique 837 636 172 355
hard.rock
Non 837 632 171 346
(100%) (99%) (99%) (97%)
Oui 0 (0%) 4 (0,6%) 1 (0,6%) 9 (2,5%)
lecture.bd
Non 813 613 172 355
(97%) (96%) (100%) (100%)
Oui 24 (2,9%) 23 (3,6%) 0 (0%) 0 (0%)
peche.chasse
Non 806 633 0 (0%) 337
(96%) (100%) (95%)
Oui 31 (3,7%) 3 (0,5%) 172 18 (5,1%)
(100%)
cuisine
Non 532 316 79 (46%) 192
(64%) (50%) (54%)
Oui 305 320 93 (54%) 163
(36%) (50%) (46%)
bricol
694
1, N = 2, N = 3, N = 4, N =
Caractéristique 837 636 172 355
Non 570 317 47 (27%) 213
(68%) (50%) (60%)
Oui 267 319 125 142
(32%) (50%) (73%) (40%)
cinema
Non 831 226 115 2 (0,6%)
(99%) (36%) (67%)
Oui 6 (0,7%) 410 57 (33%) 353
(64%) (99%)
sport
Non 834 2 (0,3%) 86 (50%) 355
(100%) (100%)
Oui 3 (0,4%) 634 86 (50%) 0 (0%)
(100%)
library(GGally)
hdv2003$typo_gower_4classes <- factor(hdv2003$typo_gower_4classes)
ggtable(
hdv2003,
columnsX = "typo_gower_4classes",
columnsY = names(d),
cells = "col.prop",
fill = "std.resid"
) +
labs(fill = "Résidus standardizés du Chi²") +
theme(legend.position = "bottom")
695
typo_gower_4classes
hard.rock
Non 100.0% 99.4% 99.4% 97.5%
lecture.bd
Non 97.1% 96.4% 100.0% 100.0%
peche.chasse
Oui 3.7% 0.5% 100.0% 5.1%
cuisine
Non 63.6% 49.7% 45.9% 54.1%
bricol
Non 68.1% 49.8% 27.3% 60.0%
1 2 3 4
696
• la troisième classe réunit spécifiquement les individus pra-
tiquant la chasse ou la pêche ;
• la quatrième classe correspond à des personnes ne prati-
quant pas de sport mais allant au cinéma.
cah_fm2$desc.var
Link between the cluster variable and the categorical variables (chi-square test)
=================================================================================
p.value df
hard.rock 0.000000e+00 4
lecture.bd 0.000000e+00 4
peche.chasse 0.000000e+00 4
cinema 0.000000e+00 4
sport 1.122743e-38 4
bricol 4.121835e-11 4
cuisine 8.681152e-04 4
697
hard.rock=hard.rock_Non 50.85599 100.00000 99.30 5.060286e-05 4.052825
hard.rock=hard.rock_Oui 0.00000 0.00000 0.70 5.060286e-05 -4.052825
cuisine=cuisine_Oui 45.28944 39.50495 44.05 3.566198e-05 -4.133925
bricol=bricol_Oui 41.61782 35.14851 42.65 6.993497e-12 -6.857788
lecture.bd=lecture.bd_Oui 0.00000 0.00000 2.35 2.518852e-15 -7.912690
sport=sport_Oui 31.25864 22.37624 36.15 6.009360e-39 -13.054257
peche.chasse=peche.chasse_Oui 0.00000 0.00000 11.20 2.188843e-75 -18.372312
cinema=cinema_Oui 0.00000 0.00000 41.30 0.000000e+00 -Inf
$`2`
Cla/Mod Mod/Cla Global p.value
peche.chasse=peche.chasse_Oui 96.428571 100.00000 11.20 2.257673e-282
bricol=bricol_Oui 14.536928 57.40741 42.65 4.149911e-06
lecture.bd=lecture.bd_Non 11.059908 100.00000 97.65 4.347616e-03
cinema=cinema_Non 12.265758 66.66667 58.70 1.129267e-02
cinema=cinema_Oui 8.716707 33.33333 41.30 1.129267e-02
lecture.bd=lecture.bd_Oui 0.000000 0.00000 2.35 4.347616e-03
bricol=bricol_Non 8.020924 42.59259 57.35 4.149911e-06
peche.chasse=peche.chasse_Non 0.000000 0.00000 88.80 2.257673e-282
v.test
peche.chasse=peche.chasse_Oui 35.908415
bricol=bricol_Oui 4.603730
lecture.bd=lecture.bd_Non 2.851773
cinema=cinema_Non 2.533509
cinema=cinema_Oui -2.533509
lecture.bd=lecture.bd_Oui -2.851773
bricol=bricol_Non -4.603730
peche.chasse=peche.chasse_Non -35.908415
$`3`
Cla/Mod Mod/Cla Global p.value v.test
cinema=cinema_Oui 86.31961 100.00000 41.30 0.000000e+00 Inf
peche.chasse=peche.chasse_Non 40.14640 100.00000 88.80 6.154083e-47 14.388011
sport=sport_Oui 52.97372 53.71669 36.15 1.222033e-33 12.088015
lecture.bd=lecture.bd_Non 36.50794 100.00000 97.65 7.397824e-10 6.157337
bricol=bricol_Oui 40.21102 48.10659 42.65 2.493205e-04 3.662957
cuisine=cuisine_Oui 39.38706 48.66760 44.05 2.003812e-03 3.089667
hard.rock=hard.rock_Non 35.90131 100.00000 99.30 2.035491e-03 3.085005
hard.rock=hard.rock_Oui 0.00000 0.00000 0.70 2.035491e-03 -3.085005
cuisine=cuisine_Non 32.70777 51.33240 55.95 2.003812e-03 -3.089667
bricol=bricol_Non 32.25806 51.89341 57.35 2.493205e-04 -3.662957
698
lecture.bd=lecture.bd_Oui 0.00000 0.00000 2.35 7.397824e-10 -6.157337
sport=sport_Non 25.84182 46.28331 63.85 1.222033e-33 -12.088015
peche.chasse=peche.chasse_Oui 0.00000 0.00000 11.20 6.154083e-47 -14.388011
cinema=cinema_Non 0.00000 0.00000 58.70 0.000000e+00 -Inf
$`4`
Cla/Mod Mod/Cla Global p.value v.test
lecture.bd=lecture.bd_Oui 100.000000 100.00000 2.35 3.168360e-96 20.814956
cinema=cinema_Oui 3.510896 61.70213 41.30 4.803168e-03 2.819946
sport=sport_Oui 3.319502 51.06383 36.15 3.601926e-02 2.096710
sport=sport_Non 1.801096 48.93617 63.85 3.601926e-02 -2.096710
cinema=cinema_Non 1.533220 38.29787 58.70 4.803168e-03 -2.819946
lecture.bd=lecture.bd_Non 0.000000 0.00000 97.65 3.168360e-96 -20.814956
$`5`
Cla/Mod Mod/Cla Global p.value v.test
hard.rock=hard.rock_Oui 100.0000000 100.00000 0.7 5.569208e-36 12.523271
cinema=cinema_Oui 1.4527845 85.71429 41.3 9.122223e-04 3.316287
cinema=cinema_Non 0.1703578 14.28571 58.7 9.122223e-04 -3.316287
hard.rock=hard.rock_Non 0.0000000 0.00000 99.3 5.569208e-36 -12.523271
699
5
4
3
2
1
cin
em
a=
cin
em
a_
N
on
pe
ch
e.c
ha
ss
e=
pe
ch
40.6 webin-R
e.c
ha
sp ss
or e_
t= N
sp on
or
t_
N
on
le
ctu
re
.b
d=
le
ctu
re
.b
d_
N
br on
ic
ol=
buant le plus
br
ic
ol_
N
on
cu
is
in
e=
cu
is
in
e_
N
on
https://youtu.be/Q8adb64NzUI
ha
rd
700
.ro
c k=
ha
rd
.ro
c k_
N
br
ic
ol=
br
ic
ol_
O
ui
le
ctu
re
.b
d=
le
ctu
re
.b
d_
O
sp ui
or
t=
sp
or
t_
O
ui
pe
ch
e.c
ha
ss
e=
pe
ch
e.c
ha
cin ss
em e_
a= O
cin ui
em
a_
O
ui
library(tidyverse)
library(labelled)
data("hdv2003", package = "questionr")
d <- hdv2003
questionr::freq(d$trav.satisf)
n % val%
Satisfaction 480 24.0 45.8
Insatisfaction 117 5.9 11.2
Equilibre 451 22.6 43.0
NA 952 47.6 NA
701
Nous allons choisir comme modalité de référence la position
intermédiaire, à savoir l’« équilibre », que nous allons donc
définir comme la première modalité du facteur.
d <- d |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
cut(
c(18, 25, 45, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45 et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
trav.satisf = "Satisfaction dans le travail",
sexe = "Sexe",
702
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
trav.imp = "Importance accordée au travail"
)
trying - sexe
trying - etudes
trying - groupe_ages
trying - trav.imp
trying - sexe
trying - etudes
trying - trav.imp
trying - etudes
trying - trav.imp
703
41.3 Affichage des résultats du modèle
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",")
tbl
704
Table 41.1: Tableau des odds ratio de la régression logistique
multinomiale
95% p-
Outcome Caractéristique OR IC valeur
Satisfaction Niveau d’études
Primaire — —
Secondaire 1,05 0,63 – 0,9
1,76
Technique / 1,08 0,67 – 0,7
Professionnel 1,73
Supérieur 2,01 1,24 – 0,005
3,27
Non documenté 0,58 0,18 – 0,4
1,86
Importance
accordée au travail
Le plus — —
Aussi 1,29 0,56 – 0,5
2,98
Moins 0,84 0,37 – 0,7
1,88
Peu 0,55 0,18 – 0,3
1,64
Insatisfaction
Niveau d’études
Primaire — —
Secondaire 0,91 0,41 – 0,8
1,99
Technique / 1,09 0,54 – 0,8
Professionnel 2,19
Supérieur 1,08 0,51 – 0,8
2,29
Non documenté 0,96 0,18 – >0,9
4,97
Importance
accordée au travail
Le plus — —
Aussi 0,80 0,24 – 0,7
2,69
705
95% p-
Outcome Caractéristique OR IC valeur
Moins 0,59 0,18 – 0,4
1,88
Peu 3,82 1,05 – 0,042
13,9
Response: trav.satisf
LR Chisq Df Pr(>Chisq)
etudes 24.211 8 0.002112 **
trav.imp 48.934 6 7.687e-09 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
706
Ď Astuce
707
tbl |> multinom_pivot_wider()
708
95% p- 95% p-
Caractéristique
OR IC valeur OR IC valeur
Niveau
d’études
Primaire — — — —
Secondaire 1,05 0,63 0,9 0,91 0,41 0,8
– –
1,76 1,99
Technique / 1,08 0,67 0,7 1,09 0,54 0,8
Profession- – –
nel 1,73 2,19
Supérieur 2,01 1,24 0,005 1,08 0,51 0,8
– –
3,27 2,29
Non 0,58 0,18 0,4 0,96 0,18 >0,9
documenté – –
1,86 4,97
Importance
accordée au
travail
Le plus — — — —
Aussi 1,29 0,56 0,5 0,80 0,24 0,7
– –
2,98 2,69
Moins 0,84 0,37 0,7 0,59 0,18 0,4
– –
1,88 1,88
Peu 0,55 0,18 0,3 3,82 1,05 0,042
– –
1,64 13,9
709
reg2 |>
ggstats::ggcoef_multinom(
exponentiate = TRUE
)
Satisfaction Insatisfaction
reg2 |>
ggstats::ggcoef_multinom(
type = "faceted",
exponentiate = TRUE
)
710
Satisfaction Insatisfaction
Niveau d'études Primaire
Secondaire
Technique / Professionnel
Supérieur
Non documenté
reg2 |>
ggstats::ggcoef_multinom(
type = "table",
exponentiate = TRUE
)
711
Satisfaction
OR 95% CI p
Niveau d'études Primaire 1.0
Secondaire 1.1 0.6, 1.80.852
Technique / Professionnel 1.1 0.7, 1.70.746
Supérieur 2.0 1.2, 3.30.005
Non documenté 0.6 0.2, 1.90.362
Insatisfaction
OR 95% CI p
Niveau d'études Primaire 1.0
Secondaire 0.9 0.4, 2.00.808
Technique / Professionnel 1.1 0.5, 2.20.815
Supérieur 1.1 0.5, 2.30.840
Non documenté 1.0 0.2, 5.00.959
reg2 |>
broom.helpers::plot_marginal_predictions() |>
patchwork::wrap_plots(ncol = 1) &
scale_y_continuous(labels = scales::percent, limits = c(0, .8)) &
coord_flip()
712
Equilibre Insatisfaction Satisfaction
Non documenté
Supérieur
Niveau d'études
Technique / Professionnel
Secondaire
Primaire
0% 20% 40% 60% 80%0% 20% 40% 60% 80%0% 20% 40% 60% 80%
Peu
Importance accordée au travail
Moins
Aussi
Le plus
0% 20% 40% 60% 80%0% 20% 40% 60% 80%0% 20% 40% 60% 80%
Ď Astuce
713
41.4 Données pondérées
remotes::install_github("carlganz/svrepmisc")
library(survey)
library(srvyr)
dw_rep <- d |>
as_survey(weights = poids) |>
as_survey_rep(type = "bootstrap", replicates = 25)
714
library(svrepmisc)
regm <- svymultinom(
trav.satisf ~ sexe + etudes + trav.imp,
design = dw_rep
)
regm
Coefficient SE t value
Satisfaction.(Intercept) -0.116149 0.778922 -0.1491
Insatisfaction.(Intercept) -1.547056 1.035410 -1.4941
Satisfaction.sexeHomme -0.041405 0.207281 -0.1998
Insatisfaction.sexeHomme 0.221849 0.225356 0.9844
Satisfaction.etudesSecondaire 0.115722 0.459004 0.2521
Insatisfaction.etudesSecondaire 0.418476 0.638761 0.6551
Satisfaction.etudesTechnique / Professionnel 0.220702 0.441744 0.4996
Insatisfaction.etudesTechnique / Professionnel 0.529317 0.526333 1.0057
Satisfaction.etudesSupérieur 0.905852 0.423886 2.1370
Insatisfaction.etudesSupérieur 0.584499 0.522629 1.1184
Satisfaction.etudesNon documenté -0.323293 1.032348 -0.3132
Insatisfaction.etudesNon documenté 0.646168 10.024786 0.0645
Satisfaction.trav.impAussi -0.027506 0.765243 -0.0359
Insatisfaction.trav.impAussi -0.375642 1.016411 -0.3696
Satisfaction.trav.impMoins -0.220703 0.764098 -0.2888
Insatisfaction.trav.impMoins -0.694337 0.992393 -0.6997
Satisfaction.trav.impPeu -0.069034 0.769459 -0.0897
Insatisfaction.trav.impPeu 1.584747 1.113253 1.4235
Pr(>|t|)
Satisfaction.(Intercept) 0.88567
Insatisfaction.(Intercept) 0.17878
Satisfaction.sexeHomme 0.84735
Insatisfaction.sexeHomme 0.35769
Satisfaction.etudesSecondaire 0.80819
Insatisfaction.etudesSecondaire 0.53331
Satisfaction.etudesTechnique / Professionnel 0.63266
Insatisfaction.etudesTechnique / Professionnel 0.34806
715
Satisfaction.etudesSupérieur 0.06994 .
Insatisfaction.etudesSupérieur 0.30031
Satisfaction.etudesNon documenté 0.76328
Insatisfaction.etudesNon documenté 0.95041
Satisfaction.trav.impAussi 0.97233
Insatisfaction.trav.impAussi 0.72263
Satisfaction.trav.impMoins 0.78107
Insatisfaction.trav.impMoins 0.50672
Satisfaction.trav.impPeu 0.93102
Insatisfaction.trav.impPeu 0.19759
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
2.5 % 97.5 %
Satisfaction.(Intercept) -1.9580078 1.7257093
Insatisfaction.(Intercept) -3.9954130 0.9013002
Satisfaction.sexeHomme -0.5315460 0.4487352
Insatisfaction.sexeHomme -0.3110326 0.7547304
Satisfaction.etudesSecondaire -0.9696491 1.2010939
Insatisfaction.etudesSecondaire -1.0919527 1.9289054
Satisfaction.etudesTechnique / Professionnel -0.8238561 1.2652610
Insatisfaction.etudesTechnique / Professionnel -0.7152623 1.7738971
Satisfaction.etudesSupérieur -0.0964784 1.9081825
Insatisfaction.etudesSupérieur -0.6513216 1.8203204
Satisfaction.etudesNon documenté -2.7644096 2.1178228
Insatisfaction.etudesNon documenté -23.0586837 24.3510192
Satisfaction.trav.impAussi -1.8370193 1.7820070
Insatisfaction.trav.impAussi -2.7790729 2.0277893
Satisfaction.trav.impMoins -2.0275093 1.5861024
Insatisfaction.trav.impMoins -3.0409735 1.6522996
Satisfaction.trav.impPeu -1.8885147 1.7504460
Insatisfaction.trav.impPeu -1.0476781 4.2171725
regm |>
broom::tidy(exponentiate = TRUE, conf.int = TRUE)
716
term estimate std.error
1 Insatisfaction.(Intercept) 0.2128737 1.0354104
2 Insatisfaction.etudesNon documenté 1.9082140 10.0247857
3 Insatisfaction.etudesSecondaire 1.5196444 0.6387607
4 Insatisfaction.etudesSupérieur 1.7940926 0.5226289
5 Insatisfaction.etudesTechnique / Professionnel 1.6977731 0.5263330
6 Insatisfaction.sexeHomme 1.2483828 0.2253557
7 Insatisfaction.trav.impAussi 0.6868483 1.0164114
8 Insatisfaction.trav.impMoins 0.4994055 0.9923930
9 Insatisfaction.trav.impPeu 4.8780580 1.1132531
10 Satisfaction.(Intercept) 0.8903423 0.7789223
11 Satisfaction.etudesNon documenté 0.7237615 1.0323485
12 Satisfaction.etudesSecondaire 1.1226842 0.4590038
13 Satisfaction.etudesSupérieur 2.4740390 0.4238857
14 Satisfaction.etudesTechnique / Professionnel 1.2469523 0.4417440
15 Satisfaction.sexeHomme 0.9594401 0.2072805
16 Satisfaction.trav.impAussi 0.9728687 0.7652434
17 Satisfaction.trav.impMoins 0.8019545 0.7640985
18 Satisfaction.trav.impPeu 0.9332946 0.7694586
statistic p.value conf.low conf.high
1 -1.49414799 0.17878189 1.839985e-02 2.462803e+00
2 0.06445701 0.95040844 9.677004e-11 3.762818e+10
3 0.65513792 0.53330874 3.355606e-01 6.881973e+00
4 1.11838317 0.30030942 5.213563e-01 6.173836e+00
5 1.00567031 0.34806462 4.890638e-01 5.893777e+00
6 0.98443901 0.35769483 7.326900e-01 2.127038e+00
7 -0.36957654 0.72262504 6.209605e-02 7.597273e+00
8 -0.69965927 0.50671773 4.778835e-02 5.218967e+00
9 1.42352820 0.19759076 3.507512e-01 6.784139e+01
10 -0.14911532 0.88566773 1.411393e-01 5.616503e+00
11 -0.31316306 0.76328136 6.301329e-02 8.313019e+00
12 0.25211645 0.80819336 3.792161e-01 3.323751e+00
13 2.13701950 0.06994146 9.080295e-01 6.740826e+00
14 0.49961614 0.63266402 4.387366e-01 3.544018e+00
15 -0.19975546 0.84735080 5.876957e-01 1.566330e+00
16 -0.03594428 0.97233033 1.592915e-01 5.941770e+00
17 -0.28884161 0.78106905 1.316631e-01 4.884673e+00
18 -0.08971810 0.93102433 1.512964e-01 5.757170e+00
717
cher un tableau basique des résultats et un graphiques des coef-
ficients, mais sans les enrichissements usuels (identification des
variables, étiquettes propres, identification des niveaux, etc.).
library(survey)
library(srvyr)
dw <- d |>
as_survey(weights = poids)
718
heures.tv (dbl), groupe_ages (fct), etudes (fct)
Coef SE z p
(Intercept):1 -0.116117 0.553242 -0.2099 0.833757
(Intercept):2 -1.547693 0.876195 -1.7664 0.077332
sexeHomme:1 -0.041412 0.171351 -0.2417 0.809029
sexeHomme:2 0.221930 0.272669 0.8139 0.415693
etudesSecondaire:1 0.115688 0.341830 0.3384 0.735034
etudesSecondaire:2 0.418102 0.563205 0.7424 0.457868
etudesTechnique / Professionnel:1 0.220662 0.310123 0.7115 0.476754
etudesTechnique / Professionnel:2 0.529020 0.501080 1.0558 0.291079
etudesSupérieur:1 0.905798 0.314513 2.8800 0.003977
etudesSupérieur:2 0.584320 0.525633 1.1116 0.266289
etudesNon documenté:1 -0.323271 0.662511 -0.4879 0.625587
etudesNon documenté:2 0.646195 0.939745 0.6876 0.491687
trav.impAussi:1 -0.027517 0.511636 -0.0538 0.957109
trav.impAussi:2 -0.374881 0.825214 -0.4543 0.649625
trav.impMoins:1 -0.220706 0.494951 -0.4459 0.655659
trav.impMoins:2 -0.693571 0.792031 -0.8757 0.381200
trav.impPeu:1 -0.069004 0.706959 -0.0976 0.922244
trav.impPeu:2 1.585521 0.866529 1.8297 0.067289
719
11 etudesNon documenté:1 0.7237778 0.4795111 0.95 0.19754885
12 etudesNon documenté:2 1.9082659 1.7932841 0.95 0.30250055
13 trav.impAussi:1 0.9728582 0.4977496 0.95 0.35689786
14 trav.impAussi:2 0.6873710 0.5672279 0.95 0.13638549
15 trav.impMoins:1 0.8019528 0.3969271 0.95 0.30398071
16 trav.impMoins:2 0.4997879 0.3958473 0.95 0.10582985
17 trav.impPeu:1 0.9333229 0.6598208 0.95 0.23348961
18 trav.impPeu:2 4.8818349 4.2302506 0.95 0.89328990
conf.high statistic df.error p.value
1 2.633247 -0.20988509 Inf 0.833757356
2 1.184853 -1.76637893 Inf 0.077332298
3 1.342360 -0.24167835 Inf 0.809029407
4 2.130488 0.81391637 Inf 0.415692863
5 2.193860 0.33843739 Inf 0.735033605
6 4.581209 0.74236198 Inf 0.457868051
7 2.289862 0.71153296 Inf 0.476754032
8 4.531799 1.05575832 Inf 0.291078645
9 4.582448 2.87999791 Inf 0.003976778
10 5.025587 1.11164951 Inf 0.266288875
11 2.651771 -0.48794745 Inf 0.625587062
12 12.037925 0.68762767 Inf 0.491687277
13 2.651888 -0.05378223 Inf 0.957108667
14 3.464290 -0.45428375 Inf 0.649624613
15 2.115688 -0.44591425 Inf 0.655659186
16 2.360279 -0.87568771 Inf 0.381199829
17 3.730751 -0.09760692 Inf 0.922244427
18 26.679258 1.82973852 Inf 0.067289048
41.5 webin-R
720
42 Régression logistique
ordinale
721
library(tidyverse)
library(labelled)
data("hdv2003", package = "questionr")
d <- hdv2003
questionr::freq(d$trav.satisf)
n % val%
Satisfaction 480 24.0 45.8
Insatisfaction 117 5.9 11.2
Equilibre 451 22.6 43.0
NA 952 47.6 NA
d <- d |>
mutate(
sexe = sexe |> fct_relevel("Femme"),
groupe_ages = age |>
722
cut(
c(18, 25, 45, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45 et plus")
),
etudes = nivetud |>
fct_recode(
"Primaire" = "N'a jamais fait d'etudes",
"Primaire" = "A arrete ses etudes, avant la derniere annee d'etudes primaires",
"Primaire" = "Derniere annee d'etudes primaires",
"Secondaire" = "1er cycle",
"Secondaire" = "2eme cycle",
"Technique / Professionnel" = "Enseignement technique ou professionnel court",
"Technique / Professionnel" = "Enseignement technique ou professionnel long",
"Supérieur" = "Enseignement superieur y compris technique superieur"
) |>
fct_na_value_to_level("Non documenté")
) |>
set_variable_labels(
trav.satisf = "Satisfaction dans le travail",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
etudes = "Niveau d'études",
trav.imp = "Importance accordée au travail"
)
723
)
Start: AIC=1978.29
trav.satisf ~ sexe + etudes + groupe_ages + trav.imp
Df AIC
- groupe_ages 2 1977.2
- sexe 1 1978.3
<none> 1978.3
- etudes 4 1991.5
- trav.imp 3 2014.0
Step: AIC=1977.23
trav.satisf ~ sexe + etudes + trav.imp
Df AIC
- sexe 1 1977.0
<none> 1977.2
- etudes 4 1990.6
- trav.imp 3 2013.2
Step: AIC=1976.97
trav.satisf ~ etudes + trav.imp
Df AIC
<none> 1977.0
- etudes 4 1990.6
- trav.imp 3 2011.6
724
traiter certains prédicteurs comme ayant un effet nominal (et
donc avec un coefficient par niveau) via l’argument nominal.
Il existe également une fonction ordinal::clmm() permet de
définir des modèles mixtes avec variables à effet aléatoire.
ĺ Important
725
42.3 Affichage des résultats du modèle
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",")
rego2 |>
tbl_regression(
exponentiate = TRUE,
tidy_fun = broom.helpers::tidy_parameters
) |>
bold_labels() |>
add_global_p(keep = TRUE)
726
Caractéristique OR 95% IC p-valeur
Primaire — —
Secondaire 1,06 0,67 – 0,8
1,67
Technique / Professionnel 1,01 0,67 – >0,9
1,53
Supérieur 1,84 1,20 – 0,006
2,83
Non documenté 0,66 0,25 – 0,4
1,72
Importance accordée <0,001
au travail
Le plus — —
Aussi 1,39 0,65 – 0,4
2,97
Moins 1,03 0,50 – >0,9
2,14
Peu 0,19 0,08 – <0,001
0,48
rego2 |>
ggstats::ggcoef_model(
exponentiate = TRUE,
tidy_fun = broom.helpers::tidy_parameters
)
727
Niveau d'études Primaire
Secondaire (p=0.794)
Supérieur (p=0.006**)
Aussi (p=0.389)
Moins (p=0.929)
Peu (p<0.001***)
0.1 0.3 1.0 3.0
OR
rego2 |>
ggstats::ggcoef_table(
exponentiate = TRUE,
tidy_fun = broom.helpers::tidy_parameters
)
OR
95% CI
p
Niveau d'études Primaire 1.0
Secondaire 1.1
0.7, 0.794
1.7
Technique / Professionnel 1.0
0.7, 0.948
1.5
Supérieur 1.8
1.2, 0.006
2.8
Non documenté 0.7
0.3, 0.393
1.7
728
Pour faciliter l’interprétation, on pourra représenter les
prédictions marginales du modèle (cf. Chapitre 24) avec
broom.helpers::plot_marginal_predictions().
rego2 |>
broom.helpers::plot_marginal_predictions() |>
patchwork::wrap_plots(ncol = 1) &
scale_y_continuous(labels = scales::percent, limits = c(0, .6)) &
coord_flip()
Non documenté
Supérieur
Niveau d'études
Technique / Professionnel
Secondaire
Primaire
Peu
Importance accordée au travail
Moins
Aussi
Le plus
729
42.4 Données pondérées
library(survey)
library(srvyr)
dw <- d |>
as_survey(weights = poids)
Calculons le modèle.
remotes::install_github("carlganz/svrepmisc")
730
library(survey)
library(srvyr)
dw_rep <- d |>
as_survey(weights = poids) |>
as_survey_rep(type = "bootstrap", replicates = 25)
library(svrepmisc)
rego6 <- svyclm(
trav.satisf ~ sexe + etudes + trav.imp,
design = dw_rep
)
Warning: (-1) Model failed to converge with max|grad| = 3.32248e-05 (tol = 1e-06)
In addition: step factor reduced below minimum
Warning: (-1) Model failed to converge with max|grad| = 0.000185935 (tol = 1e-06)
In addition: step factor reduced below minimum
rego6
731
Equilibre|Satisfaction 0.27271800 0.62106791 0.4391 0.666840
sexeHomme -0.13280477 0.12200420 -1.0885 0.293544
etudesSecondaire -0.04271403 0.32974824 -0.1295 0.898655
etudesTechnique / Professionnel 0.00042809 0.20659834 0.0021 0.998374
etudesSupérieur 0.64247607 0.31224371 2.0576 0.057445 .
etudesNon documenté -0.46945975 0.54448991 -0.8622 0.402151
trav.impAussi 0.12071087 0.57298613 0.2107 0.835980
trav.impMoins 0.05267146 0.56245266 0.0936 0.926630
trav.impPeu -1.53039056 0.84702657 -1.8068 0.090895 .
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
2.5 % 97.5 %
Insatisfaction|Equilibre -3.43341816 -0.6449312
Equilibre|Satisfaction -1.05105691 1.5964929
sexeHomme -0.39285057 0.1272410
etudesSecondaire -0.74555577 0.6601277
etudesTechnique / Professionnel -0.43992586 0.4407820
etudesSupérieur -0.02305565 1.3080078
etudesNon documenté -1.63001252 0.6910930
trav.impAussi -1.10058016 1.3420019
trav.impMoins -1.14616801 1.2515109
trav.impPeu -3.33578496 0.2750038
rego6 |>
broom::tidy(exponentiate = TRUE, conf.int = TRUE)
732
9 trav.impMoins 1.0540833 0.5624527 0.093646033 0.926629750
10 trav.impPeu 0.2164511 0.8470266 -1.806779867 0.090895149
conf.low conf.high
1 0.34956809 4.9356921
2 0.19592712 1.9958959
3 0.47447053 1.9350394
4 0.97720810 3.6987976
5 0.64408417 1.5539220
6 0.03227643 0.5246987
7 0.67512962 1.1356907
8 0.33267802 3.8266965
9 0.31785245 3.4956206
10 0.03558664 1.3165357
library(survey)
library(srvyr)
dw <- d |>
as_survey(weights = poids)
733
)
rego7 |> summary()
734
4 etudesSecondaire 1.0436383 0.29741869 0.95 0.59699738
5 etudesTechnique / Professionnel 0.9995700 0.25709290 0.95 0.60378349
6 etudesSupérieur 0.5259877 0.13986079 0.95 0.31234891
7 etudesNon documenté 1.5991274 0.84020546 0.95 0.57101702
8 trav.impAussi 0.8862897 0.43007677 0.95 0.34239361
9 trav.impMoins 0.9486910 0.44616524 0.95 0.37740568
10 trav.impPeu 4.6198737 3.01013253 0.95 1.28830837
conf.high statistic df.error p.value
1 0.3639179 -3.886538948 Inf 0.0001016836
2 3.5912276 0.531453766 Inf 0.5951043720
3 1.5450672 0.861141383 Inf 0.3891601794
4 1.8244316 0.149879202 Inf 0.8808599211
5 1.6547990 -0.001671995 Inf 0.9986659418
6 0.8857499 -2.416225817 Inf 0.0156823321
7 4.4783403 0.893499744 Inf 0.3715896094
8 2.2941709 -0.248758549 Inf 0.8035475563
9 2.3847407 -0.111997880 Inf 0.9108250872
10 16.5668669 2.348768359 Inf 0.0188356206
735
43 Modèles de comptage
(Poisson & apparentés)
736
femmes à l’âge de 30 ans.
library(tidyverse)
library(labelled)
data("fecondite", package = "questionr")
[1] masculin
[2] féminin
[0] non
[1] oui
737
un fichier Stata ou SPSS avec {haven}. Première étape, nous
allons convertir à la volée ces variables catégorielles en facteurs
avec labelled::unlabelled().
femmes <-
femmes |>
unlabelled()
enfants <-
enfants |>
unlabelled()
enfants <-
enfants |>
left_join(
femmes |>
select(id_femme, date_naissance_mere = date_naissance),
by = "id_femme"
) |>
mutate(
age_mere = time_length(
date_naissance_mere %--% date_naissance,
unit = "years"
)
)
femmes <-
femmes |>
left_join(
enfants |>
738
filter(age_mere < 30) |>
group_by(id_femme) |>
count(name = "enfants_avt_30"),
by = "id_femme"
) |>
tidyr::replace_na(list(enfants_avt_30 = 0L))
femmes <-
femmes |>
mutate(
age = time_length(
date_naissance %--% date_entretien,
unit = "years"
),
educ2 = educ |>
fct_recode(
"secondaire/supérieur" = "secondaire",
"secondaire/supérieur" = "supérieur"
)
)
Enfin, pour l’analyse, nous n’allons garder que les femmes âgées
d’au moins 30 ans au moment de l’enquête. En effet, les femmes
plus jeunes n’ayant pas encore atteint 30 ans, nous ne connais-
sons pas leur descendance atteinte à cet âge.
femmes30p <-
femmes |>
filter(age >= 30)
739
la fonction stats::glm() en précisant family = poisson.
Start: AIC=1013.81
enfants_avt_30 ~ educ2 + milieu + region
Df Deviance AIC
- region 3 686.46 1010.6
<none> 683.62 1013.8
- milieu 1 686.84 1015.0
- educ2 2 691.10 1017.3
Step: AIC=1010.65
enfants_avt_30 ~ educ2 + milieu
Df Deviance AIC
<none> 686.46 1010.6
- milieu 1 691.30 1013.5
- educ2 2 693.94 1014.1
740
car la régression de Poisson peut également être utilisée pour
des modèles d’incidence, qui seront abordés dans le prochain
chapitre (cf. Chapitre 44).
Pour un tableau mis en forme des coefficients, on aura
tout simplement recours à {gtsummary} et sa fonction
gtsummary::tbl_regression().
library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",", big.mark = " ")
mod1_poisson |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
library(ggstats)
mod1_poisson |>
741
ggcoef_table(exponentiate = TRUE)
IRR95% CI p
Niveau d'éducation
aucun 1.0
Milieu de résidence
urbain 1.0
broom.helpers::plot_marginal_predictions(mod1_poisson) |>
patchwork::wrap_plots() &
ggplot2::scale_y_continuous(limits = c(0, .4))
742
0.4 0.4
0.3 0.3
0.2 0.2
0.1 0.1
0.0 0.0
aucun primaire
secondaire/supérieur urbain rural
Niveau d'éducation Milieu de résidence
743
df <- dplyr::tibble(
status = c(
rep.int("observed", length(observed)),
rep.int("theoretical", length(theoretical))
),
values = c(observed, theoretical)
)
if (is.numeric(observed) && any(observed != as.integer(observed))) {
ggplot2::ggplot(df) +
ggplot2::aes(x = values, fill = status) +
ggplot2::geom_density(
alpha = .5,
position = "identity"
) +
ggplot2::theme_light() +
ggplot2::labs(fill = NULL)
} else {
ggplot2::ggplot(df) +
ggplot2::aes(x = values, fill = status) +
ggplot2::geom_bar(
alpha = .5,
position = "identity"
) +
ggplot2::theme_light() +
ggplot2::theme(
panel.grid.major.x = ggplot2::element_blank(),
panel.grid.minor.x = ggplot2::element_blank()
) +
ggplot2::labs(fill = NULL)
}
}
mod1_poisson |>
observed_vs_theoretical()
744
600
400
count
observed
theoretical
200
0
0 2 4
values
Ĺ Note
mod1_poisson |>
performance::check_predictions(type = "discrete_both")
745
Posterior Predictive Check
Model−predicted points should be close to observed data points
600
400
Counts
Observed data
Model−predicted data
200
0
0 1 2 3 4 5
enfants_avt_30
mod1_poisson$deviance / mod1_poisson$df.residual
[1] 0.8580717
746
La package {AER} propose un test, AER::dispersiontest(),
pour tester s’il y a un problème de surdispersion. Ce test ne
peut s’appliquer qu’à un modèle de Poisson.
Overdispersion test
data: mod1_poisson
z = 3.3367, p-value = 0.0004238
alternative hypothesis: true dispersion is greater than 1
sample estimates:
dispersion
1.361364
mod1_poisson |>
performance::check_overdispersion()
# Overdispersion test
Overdispersion detected.
Dans les deux cas, nous obtenons une p-valeur inférieure à 0,001,
indiquant que le modèle de Poisson n’est peut-être pas appro-
prié ici.
747
variance qui est alors modélisée comme une relation linéaire de
la moyenne. Il se calcule également avec stats::glm(), mais
en indiquant family = quasipoisson. Comme avec le modèle
de Poisson, la fonction de lien par défaut est la fonction loga-
rithmique (log).
ĺ Important
mod1_quasi |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
748
Caractéristique IRR 95% IC p-valeur
urbain — —
rural 1,42 0,99 – 2,10 0,067
Niveau d'éducation
aucun
primaire
secondaire/supérieur
Milieu de résidence
urbain
rural
Poisson quasi−Poisson
749
mod1_quasi |>
performance::check_overdispersion()
# Overdispersion test
Overdispersion detected.
Start: AIC=979.1
enfants_avt_30 ~ educ2 + milieu + region
Df Deviance AIC
- region 3 462.89 975.01
750
<none> 460.98 979.10
- milieu 1 463.29 979.41
- educ2 2 466.11 980.22
Step: AIC=975
enfants_avt_30 ~ educ2 + milieu
Df Deviance AIC
<none> 460.14 975.00
- milieu 1 463.37 976.24
- educ2 2 465.54 976.40
mod1_nb |>
tbl_regression(exponentiate = TRUE) |>
bold_labels()
751
list(
Poisson = mod1_poisson,
"quasi-Poisson" = mod1_quasi,
"Binomial négatif" = mod1_nb
) |>
ggcoef_compare(exponentiate = TRUE)
Niveau d'éducation
aucun
primaire
secondaire/supérieur
Milieu de résidence
urbain
rural
mod1_nb |>
observed_vs_theoretical()
mod1_nb |>
performance::check_predictions(type = "discrete_both")
752
600
400
count
observed
theoretical
200
0
0 2 4
values
600
400
Counts
Observed data
Model−predicted data
200
0
0 5 10
enfants_avt_30
753
mod1_nb |>
performance::check_overdispersion()
# Overdispersion test
No overdispersion detected.
performance::compare_performance(
mod1_poisson,
mod1_nb,
metrics = "common"
)
754
Préparons les données en francisant les facteurs et en ajoutant
des étiquettes de variable.
mod2_poisson |>
observed_vs_theoretical()
755
15
count
10 observed
theoretical
0
0 20 40 60 80
values
mod2_poisson |>
performance::check_overdispersion()
# Overdispersion test
Overdispersion detected.
756
data = d
)
mod2_nb |>
observed_vs_theoretical()
15
count
10 observed
theoretical
0
0 25 50 75 100
values
mod2_nb |>
performance::check_overdispersion()
# Overdispersion test
No overdispersion detected.
757
Voilà !
Pour finir, visualisons les coefficients du modèle.
mod2_nb |>
ggcoef_table(exponentiate = TRUE)
IRR95% CI p
Sexe de l'enfant
fille 1.0
Vitesse d'apprentissage
dans la moyenne 1.0
0.8 0.91.0
IRR
758
data(hdv2003, package = "questionr")
d <-
hdv2003 |>
mutate(
groupe_ages = age |>
cut(
c(18, 25, 45, 65, 99),
right = FALSE,
include.lowest = TRUE,
labels = c("18-24 ans", "25-44 ans",
"45-64 ans", "65 ans et plus")
)
) |>
set_variable_labels(
sport = "Pratique un sport ?",
sexe = "Sexe",
groupe_ages = "Groupe d'âges",
heures.tv = "Heures de télévision / jour"
)
levels(d$sexe)
759
Nous allons maintenant calculer un modèle de Poisson. Nous
devons déjà ré-exprimer notre variable à expliquer sous la forme
d’une variable numérique égale à 0 si l’on ne pratique pas de
sport et à 1 si l’on pratique un sport.
levels(d$sport)
performance::check_overdispersion(mod3_poisson)
# Overdispersion test
No overdispersion detected.
mod3_binomial |>
ggstats::ggcoef_table(exponentiate = TRUE)
760
OR95% CI p
Sexe Homme 1.61.3, 1.9
<0.001
Femme 1.0
mod3_poisson |>
ggstats::ggcoef_table(exponentiate = TRUE)
IRR95% CI p
Sexe Homme 1.31.1, 1.5
<0.001
Femme 1.0
Nous pouvons voir ici que les deux modèles fournissent des résul-
761
tats assez proches. Par contre, les coefficients ne s’interprètent
pas de la même manière. Dans le cadre de la régression lo-
gistique, il s’agit d’odds ratios (ou rapports des côtes) définis
𝑝𝐴 𝑝𝐵
comme 𝑂𝑅𝐴/𝐵 = ( 1−𝑝 )/( 1−𝑝 ) où 𝑝𝐴 correspond à la proba-
𝐴 𝐵
bilité de faire du sport pour la modalité 𝐴. Pour la régression
de Poisson, il s’agit de prevalence ratios (rapports des préva-
lences) définis comme 𝑃 𝑅𝐴/𝐵 = 𝑝𝐴 /𝑝𝐵 . Avec un rapport des
prévalences de 1,3, nous pouvons donc dire que, selon le modèle,
les hommes ont 30% de chance en plus de pratiquer un sport.
Pour mieux comparer les deux modèles, nous pouvons présenter
les résultats sous la forme de contrastes marginaux moyens (cf.
Section 24.4) qui, pour rappel, sont exprimés dans l’échelle de
la variable d’intérêt, soit ici sous la forme d’une différence de
probabilité.
list(
"régression logistique" = mod3_binomial,
"régression de Poisson" = mod3_poisson
) |>
ggcoef_compare(tidy_fun = broom.helpers::tidy_marginal_contrasts) +
scale_x_continuous(labels = scales::percent)
Sexe
Femme − Homme
Groupe d'âges
25−44 ans − 18−24 ans
762
Les résultats sont ici très proches. Nous pouvons néanmoins
constater que les intervalles de confiance pour la régression
de Poisson sont un peu plus large. Nous pouvons comparer
les deux modèles avec performance::compare_performance()
pour constater que, dans notre exemple, la régression de Pois-
son est un peu moins bien ajustée aux données que la régression
logistique binaire. Cependant, en pratique, cela n’est pas ici pro-
blématique : le choix entre les deux modèles peut donc se faire
en fonction de la manière dont on souhaite présenter et narrer
les résultats.
performance::compare_performance(
mod3_binomial,
mod3_poisson,
metrics = "common"
)
Ď Astuce
763
Il faut noter que ce type de modèles a parfois du mal à
converger.
Error: impossible de trouver un jeu de coefficients correct : prière de fournir des valeurs i
mod3_log |>
ggstats::ggcoef_table(exponentiate = TRUE)
764
RR95% CI p
Sexe Homme 1.31.2, 1.4
<0.001
Femme 1.0
mod3_logbin |>
ggstats::ggcoef_table(exponentiate = TRUE)
Warning: The `tidy()` method for objects of class `logbin` is not maintained by the broom tea
765
RR95% CI p
Sexe Homme 1.31.2, 1.4
<0.001
Femme 1.0
library(srvyr)
library(survey)
dp <- d |>
as_survey_design(weights = poids)
mod4_poisson <- svyglm(
sport2 ~ sexe + groupe_ages + heures.tv,
family = poisson,
design = dp
)
mod4_quasi <- svyglm(
sport2 ~ sexe + groupe_ages + heures.tv,
1
Sur ce sujet, on pourra consulter l’article Log-binomial models: explo-
ring failed convergence par Tyler Williamson, Misha Eliasziw et Gor-
don Hilton Fick, DOI: 10.1186/1742-7622-10-14. On pourra également
consulter cet échange sur StackExchange.
766
family = quasipoisson,
design = dp
)
Ĺ Note
767
dp_rep <- dp |>
as_survey_rep(type = "bootstrap", replicates = 100)
mod4_nb_alt <- svrepmisc::svynb(
sport2 ~ sexe + groupe_ages + heures.tv,
design = dp_rep
)
768
44 Modèles d’incidence / de
taux
769
retombons sur un modèle de comptage classique, à condition
d’ajouter à chaque observation ce qu’on appelle un décalage
(offset en anglais) de 𝑙𝑜𝑔(𝑑𝑒𝑥𝑝 ). Ce décalage correspond donc
en quelque sorte à une variable ajoutée au modèle mais pour
laquelle on ne calcule pas de coefficient.
770
)
mod1_poisson_alt <- glm(
death ~ stage + trt + response,
offset = log(ttdeath),
family = poisson,
data = gtsummary::trial
)
mod1_poisson |>
performance::check_overdispersion()
# Overdispersion test
No overdispersion detected.
mod1_poisson |>
ggstats::ggcoef_table(exponentiate = TRUE)
771
IRR 95% CI p
T Stage T1 1.0
772
d <- MASS::Insurance
d$Age <- factor(d$Age, ordered = FALSE)
d$Group <- factor(d$Group, ordered = FALSE)
mod2_poisson <- glm(
Claims ~ Age + Group + offset(log(Holders)),
family = poisson,
data = d
)
mod2_poisson |>
performance::check_overdispersion()
# Overdispersion test
No overdispersion detected.
mod2_poisson |>
ggstats::ggcoef_table(exponentiate = TRUE)
773
IRR 95% CI p
Age <25 1.0
774
puisque, pour les femmes de plus de 25 ans à l’enquête, la
durée d’exposition entre 15 et 25 ans exacts est de 10 ans.
library(tidyverse)
library(labelled)
data("fecondite", package = "questionr")
femmes <-
femmes |>
unlabelled() |>
mutate(
age = time_length(
date_naissance %--% date_entretien,
unit = "years"
),
exposition = if_else(age <= 25, age - 15, 10),
educ2 = educ |>
fct_recode(
"secondaire/supérieur" = "secondaire",
"secondaire/supérieur" = "supérieur"
)
) |>
# exclure celles qui viennent juste d'avoir 15 ans
filter(exposition > 0)
enfants <-
enfants |>
unlabelled() |>
left_join(
femmes |>
select(id_femme, date_naissance_mere = date_naissance),
by = "id_femme"
) |>
mutate(
age_mere = time_length(
date_naissance_mere %--% date_naissance,
unit = "years"
)
775
)
femmes <-
femmes |>
left_join(
enfants |>
filter(age_mere >= 15 & age_mere < 25) |>
group_by(id_femme) |>
count(name = "enfants_15_24"),
by = "id_femme"
) |>
tidyr::replace_na(list(enfants_15_24 = 0L))
Vérifions la surdispersion.
mod3_poisson |>
performance::check_overdispersion()
# Overdispersion test
Overdispersion detected.
776
)
mod3_nb |>
performance::check_overdispersion()
# Overdispersion test
No overdispersion detected.
mod3_nb |>
ggstats::ggcoef_table(exponentiate = TRUE)
IRR95% CI p
Niveau d'éducation
aucun 1.0
Milieu de résidence
urbain 1.0
777
Poisson) avec R par Claire Della Vedova
• Zoom sur la Regression de Poisson et l’Incidence Risque
Ratio (IRR) : exemple du vaccin anti-SarsCov2 d’Oxford
par Ihsane Hmamouchi
778
45 Modèles de comptage
zero-inflated et hurdle
library(labelled)
library(tidyverse)
data("DebTrivedi", package = "MixAll")
d <- DebTrivedi |>
mutate(
779
gender = gender |>
fct_recode("femme" = "female", "homme" = "male"),
privins = privins |>
fct_recode("non" = "no", "oui" = "yes"),
health = health |>
fct_recode(
"pauvre" = "poor",
"moyenne" = "average",
"excellente" = "excellent"
)
) |>
set_variable_labels(
ofp = "Nombre de visites médicales",
gender = "Genre de l'assuré",
privins = "Dispose d'une assurance privée ?",
health = "Santé perçue",
numchron = "Nombre de conditions chroniques"
)
contrasts(d$health) <- contr.treatment(3, base = 2)
# Overdispersion test
780
p-value = < 0.001
Overdispersion detected.
# Overdispersion test
Overdispersion detected.
781
Posterior Predictive Check
Model−predicted intervals should include observed data points
600
Counts
400
Observed data
Model−predicted data
200
0
0 5 10 15 20
ofp
782
Calculons un premier modèle de Poisson zero-inflated.
mod_zip |>
ggstats::ggcoef_multicomponents(
type = "table",
exponentiate = TRUE,
intercept = TRUE
)
783
conditional
exp(Beta) 95% CI p
(Intercept) 4.8 4.7, 5.0 <0.001
zero_inflated
exp(Beta) 95% CI p
(Intercept) 0.6 0.5, 0.7 <0.001
784
modèles de Poisson zero-inflated simplifiés où seul un intercept
est utilisé pour la composante logistique binaire.
mod_zip_simple |>
ggstats::ggcoef_multicomponents(
type = "table",
tidy_fun = broom.helpers::tidy_zeroinfl,
exponentiate = TRUE,
intercept = TRUE,
component_label = c(
conditional = "Modèle de Poisson",
zero_inflated = "Modèle logistique binaire"
)
) +
patchwork::plot_layout(heights = c(6, 1))
785
Modèle de Poisson
exp(Beta) 95% CI p
(Intercept) 4.8 4.6, 5.0 <0.001
performance::compare_performance(
mod_poisson,
mod_zip_simple,
mod_zip,
786
mod_nb,
mod_zinb,
metrics = "AIC"
)
library(gtsummary)
tbl_nb <- mod_nb |>
tbl_regression(exponentiate = TRUE)
tbl_zinb <- mod_zinb |>
tbl_regression(
tidy_fun = broom.helpers::tidy_zeroinfl,
component = "conditional",
exponentiate = TRUE
)
list(tbl_nb, tbl_zinb) |>
tbl_merge(c("**NB**", "**ZI-NB**")) |>
bold_labels()
787
Table 45.1: Coefficients du modèle négatif binomial et de la
composante comptage du modèle négatif binomial
zero-inflated
95% p- 95% p-
Characteristic IRR CI value exp(Beta)
CI value
Genre de
l’assuré
femme — — — —
homme 0.90 0.84, <0.001 0.93 0.88, 0.031
0.95 0.99
Dispose
d’une
assurance
privée ?
non — — — —
oui 1.39 1.29, <0.001 1.23 1.14, <0.001
1.50 1.33
Santé perçue
pauvre 1.39 1.27, <0.001 1.38 1.26, <0.001
1.53 1.51
moyenne — — — —
excellente 0.71 0.63, <0.001 0.71 0.63, <0.001
0.80 0.81
Nombre de 1.21 1.19, <0.001 1.16 1.13, <0.001
conditions 1.25 1.19
chroniques
788
Si l’objectif de l’analyse est avant d’identifier les facteurs asso-
ciés avec le nombre moyen d’évènement, on pourra éventuelle-
ment se contenter d’un modèle zero-inflated simple, c’est-à-dire
avec seulement un intercept pour la composante zero-inflated
afin de corriger la sur-représentation des zéros dans nos don-
nées.
Alternativement, on pourra se tourner vers un modèle avec saut
qui distingue les valeurs nulles des valeurs positives : les modèles
hurdle en anglais.
789
parce qu’ils n’ont pas manifesté de tels comportements à risque
au cours de la période étudiée. La probabilité d’appartenir à
l’une ou l’autre population est estimée à l’aide d’une compo-
sante de probabilité à inflation nulle, tandis que les effectifs
de la seconde population du groupe d’utilisateurs sont modé-
lisés par une distribution de comptage ordinaire, telle qu’une
distribution de Poisson ou binomiale négative.
En revanche, un modèle hurdle suppose que toutes les données
nulles proviennent d’une source “structurelle”, une partie du
modèle étant un modèle binaire pour modéliser si la variable
de réponse est nulle ou positive, et une autre partie utilisant
un modèle tronqué, pour les données positives. Par exemple,
dans les études sur l’utilisation des soins de santé, la partie
zéro implique la décision de rechercher des soins, et la compo-
sante positive détermine la fréquence de l’utilisation au sein du
groupe de l’utilisateur.
Une autre différence importante entre les modèles hurdle et
zero-inflated est leur capacité à gérer la déflation zéro (moins
de zéros que prévu par le processus de génération des données).
Les modèles zero-inflated ne sont pas en mesure de gérer la dé-
flation zéro, quel que soit le niveau d’un facteur, et donneront
des estimations de paramètres de l’ordre de l’infini pour la com-
posante logistique, alors que les modèles hurdle peuvent gérer
la déflation zéro (Min et Agresti 2005).
Min, Yongyi, et Alan Agresti. 2005.
Les modèles hurdle peuvent être calculés avec la fonc- « Random Effect Models for Repea-
ted Measures of Zero-Inflated Count
tion pscl::hurdle() dont la syntaxe est similaire à Data ». Statistical Modelling 5 (1):
pscl::zeroinfl(). 1‑19. https://doi.org/10.1191/1471
082X05st084oa.
mod_hurdle_poisson <- pscl::hurdle(
ofp ~ gender + privins + health + numchron,
data = d
)
mod_hurdle_nb <- pscl::hurdle(
ofp ~ gender + privins + health + numchron,
dist = "negbin",
data = d
)
790
mod_hurdle_nb |>
ggstats::ggcoef_multicomponents(
type = "table",
tidy_fun = broom.helpers::tidy_zeroinfl,
exponentiate = TRUE,
component_label = c(
conditional = "Facteurs associés au nombre d'évènements",
zero_inflated = "Facteurs associés au fait d'avoir vécu l'évènement"
)
)
moyenne 1.0
moyenne 1.0
1 2 3
exp(Beta)
791
• Si l’on a vécu l’évènement au moins une fois, quels sont
les facteurs associés à la fréquence de l’évènement ?
792
• A comparison of zero-inflated and hurdle models for mo-
deling zero-inflated count data par Cindy Xin Feng. DOI :
10.1186/s40488-021-00121-4
• Zero-inflated models for adjusting varying exposures: a
cautionary note on the pitfalls of using offset by Cindy
Xin Feng. DOI : 10.1080/02664763.2020.1796943
793
46 Quel modèle choisir ?
794
partie VII
795
47 Ressources documentaires
796
• R for Non-Programmers: A Guide for Social Scientists
par Daniel Dauber
797