7 Statistiques descriptives

Ce chapitre vous permet de mobiliser vos connaissances acquises avec le chapitre sur les tableaux de données et le chapitre sur R Markdown pour produire rapidement des résumés statistiques à partir de données tabulaires.

7.1 Données du chapitre

Dans ce chapitre, vous allez manipuler des données qui proviennent de l’article de Bertrand and Mullainathan (2004) intitulé Are Emily and Greg More Employable Than Lakisha and Jamal?, dans lequel les auteurs se sont penchés sur l’existence de discrimination sur le marché du travail aux États-Unis. Dans leur travail, les chercheurs ont envoyé des faux CVs en réponse à des annonces postées dans des journeaux à Boston et à Chicago. Ces faux CVs ont été réalisés de manière aléatoire, en faisant varier diverses caractéristiques : le genre de la personne qui postule, la qualité de rédaction, l’expérience, le niveau d’études, etc. Ce qui intéresse les auteurs est de mesurer la discrimination raciale. Plutôt que d’indiquer l’ethnicité des personnes sur les CVs, les auteurs ont choisi de donner des noms à consonnance afro-américaine ou caucasienne aux faux CVs, en attribuant de manière aléatoire les noms aux faux CVs.

Le package {AER} fournit les données de l’étude. Si ce package n’est pas installé sur votre machine, vous pouvez l’installer comme suit :

install.packages("AER")

Ensuite, vous pouvez charger le jeu de données ResumeNames comme suit :

data(ResumeNames, package = "AER")

Pour afficher la page d’aide du jeu de données ResumeNames et ainsi accéder au descriptif des variables, vous pouvez écrire dans la console R :

help("ResumeNames", package = "AER")

Nous allons nous concentrer sur les variables listées dans le Tableau 7.1 (libre à vous d’en conserver davantage par la suite pour explorer ces données) :

Table 7.1: Caractéristiques des fichiers texte avec séparateur de champ
Variable Description
name Prénom de la personne qui postule (personne fictive)
gender Genre de la personne qui postule (female ou male)
ethnicity Ethnicité de la personne qui postule (cauc: prénom à consonnance caucasienne ou afam : prénom à consonnance afro-américaine)
call La personne qui postule a-t-elle été rappelée ? (no ou yes)
city Ville concernée par l’annonce (chicago ou boston)
jobs Nombre d’emplois précédents listés dans le CV
experience Nombre d’années d’expériences listées dans le CV

Créons un objet contenant uniquement les colonnes mentionnées dans le Tableau 7.1.

resumes <- 
  ResumeNames %>% 
  select(name, gender, ethnicity, call, city, jobs, experience) %>% 
  as_tibble()
resumes
## # A tibble: 4,870 × 7
##    name    gender ethnicity call  city     jobs experience
##    <fct>   <fct>  <fct>     <fct> <fct>   <int>      <int>
##  1 Allison female cauc      no    chicago     2          6
##  2 Kristen female cauc      no    chicago     3          6
##  3 Lakisha female afam      no    chicago     1          6
##  4 Latonya female afam      no    chicago     4          6
##  5 Carrie  female cauc      no    chicago     3         22
##  6 Jay     male   cauc      no    chicago     2          6
##  7 Jill    female cauc      no    chicago     2          5
##  8 Kenya   female afam      no    chicago     4         21
##  9 Latonya female afam      no    chicago     3          3
## 10 Tyrone  male   afam      no    chicago     2          6
## # ℹ 4,860 more rows

7.2 Résumés statistiques à la main

Dans un premier temps, il faut apprendre à connaître le contenu des données, fouiller dedans. Cette étape primordiale dans tout projet permet bien souvent de déceler des erreurs dans les données, ou de soulever des questions nécessitant un traitement spécifique.

7.2.1 Dimensions, résumés grossiers

La première chose à savoir sur un jeu de données est la suivante : quelles en sont ses dimensions ? Nous souhaitons connaître le nombre d’observations (\(n\)) et le nombre de colonnes (\(p\)). Nous l’avons vu dans le chapitre portant sur les tableaux de données, pour ce faire, la fonction dim() est très pratique :

dim(resumes)
## [1] 4870    7

Un simple affichage du tableau de données dans la console permet par ailleurs d’avoir accès à ces informations. L’avantage de dim() est que les valeurs peuvent être stockées dans un objet et réutilisées ensuite (dans le cadre de la réalisation de boucles, par exemple).

Pour avoir un aperçu grossier du tableau de données, nous pouvons utiliser la fonction summary() :

summary(resumes)
##       name         gender     ethnicity    call           city     
##  Tamika : 256   male  :1124   cauc:2435   no :4478   boston :2166  
##  Anne   : 242   female:3746   afam:2435   yes: 392   chicago:2704  
##  Allison: 232                                                      
##  Latonya: 230                                                      
##  Emily  : 227                                                      
##  Latoya : 226                                                      
##  (Other):3457                                                      
##       jobs         experience    
##  Min.   :1.000   Min.   : 1.000  
##  1st Qu.:3.000   1st Qu.: 5.000  
##  Median :4.000   Median : 6.000  
##  Mean   :3.661   Mean   : 7.843  
##  3rd Qu.:4.000   3rd Qu.: 9.000  
##  Max.   :7.000   Max.   :44.000  
## 

Pour chaque variable, en fonction de son type, des informations sont proposées :

  • pour des variables numériques : moyenne, étendue, quartiles ;
  • pour des variables catégorielles : la fréquence des 6 premières valeurs les plus présentes.

Pour la variable name du tableau resumes, nous pouvons voir qu’il semble y avoir plus de 6 valeurs. Nous pouvons les lister avec la fonction unique() :

unique(resumes$name)
##  [1] Allison  Kristen  Lakisha  Latonya  Carrie   Jay      Jill     Kenya   
##  [9] Tyrone   Aisha    Geoffrey Matthew  Tamika   Leroy    Todd     Greg    
## [17] Keisha   Brad     Laurie   Meredith Anne     Emily    Latoya   Ebony   
## [25] Brendan  Hakim    Jamal    Neil     Tremayne Brett    Darnell  Sarah   
## [33] Jermaine Tanisha  Rasheed  Kareem  
## 36 Levels: Allison Anne Carrie Emily Jill Laurie Kristen Meredith ... Tyrone

Pour dénombrer la fréquence de chaque modalité d’une variable catégorielle, on peut utiliser la fonction table() :

table(resumes$name)
## 
##  Allison     Anne   Carrie    Emily     Jill   Laurie  Kristen Meredith 
##      232      242      168      227      203      195      213      187 
##    Sarah     Brad  Brendan Geoffrey     Greg    Brett      Jay  Matthew 
##      193       63       65       59       51       59       67       67 
##     Neil     Todd    Aisha    Ebony   Keisha    Kenya  Lakisha  Latonya 
##       76       68      180      208      183      196      200      230 
##   Latoya   Tamika  Tanisha  Darnell    Hakim    Jamal Jermaine   Kareem 
##      226      256      207       42       55       61       52       64 
##    Leroy  Rasheed Tremayne   Tyrone 
##       64       67       69       75

Rien ne nous empêche de trier les résultats avec la fonction sort() :

sort(table(resumes$name))
## 
##  Darnell     Greg Jermaine    Hakim Geoffrey    Brett    Jamal     Brad 
##       42       51       52       55       59       59       61       63 
##   Kareem    Leroy  Brendan      Jay  Matthew  Rasheed     Todd Tremayne 
##       64       64       65       67       67       67       68       69 
##   Tyrone     Neil   Carrie    Aisha   Keisha Meredith    Sarah   Laurie 
##       75       76      168      180      183      187      193      195 
##    Kenya  Lakisha     Jill  Tanisha    Ebony  Kristen   Latoya    Emily 
##      196      200      203      207      208      213      226      227 
##  Latonya  Allison     Anne   Tamika 
##      230      232      242      256

Exercice

  1. En utilisant la fonction table(), affichez le nombre de réponses “no” et “yes” pour le jeu de données resumes. Stockez le résultat dans une variable que vous nommerez freq_reponses.
  2. Il est possible d’accéder aux éléments d’un objet de type table à l’aide des crochets simples ([]). En utilisant les crochets sur l’objet freq_reponses, calculez la proportion de “yes” dans le jeu de données.

7.2.2 Exploration des valeurs avec des tableaux

7.2.2.1 Tableaux à double entrée

La fonction table() est également très pratique pour faire des tableaux croisés. Pour ce faire, il convient de fournir en argument les vecteurs de valeurs (contenant des variables catégorielles de type character ou factor). Par exemple, dans l’article dont les données de ce chapitre sont issues, nous pouvons regarder combien de candidatures ont reçu ou non un retour, selon l’ethnicité :

call_ethnicity_tb <- 
  table(resumes$call, resumes$ethnicity)
call_ethnicity_tb
##      
##       cauc afam
##   no  2200 2278
##   yes  235  157

Pour davantage de lisibilité du tableau, les arguments de la fonction peuvent être nommés ; le tableau croisé affichera ainsi une étiquette pour les lignes et les colonnes :

call_ethnicity_tb <- table(call = resumes$call, ethnicity = resumes$ethnicity)
call_ethnicity_tb
##      ethnicity
## call  cauc afam
##   no  2200 2278
##   yes  235  157

Les marges peuvent être ajoutées avec la fonction addmargins() :

addmargins(call_ethnicity_tb)
##      ethnicity
## call  cauc afam  Sum
##   no  2200 2278 4478
##   yes  235  157  392
##   Sum 2435 2435 4870

Pour obtenir les proportions sans avoir à utiliser les crochets comme dans l’exercice plus haut, R propose la fonction prop.table(), que l’on applique au tableau croisé :

prop.table(table(call = resumes$call, ethnicity = resumes$ethnicity))
##      ethnicity
## call        cauc       afam
##   no  0.45174538 0.46776181
##   yes 0.04825462 0.03223819

Ou en utilisant l’opérateur pipe (%>%) pour davantage de lisibilité :

table(call = resumes$call, ethnicity = resumes$ethnicity) %>% 
  prop.table()
##      ethnicity
## call        cauc       afam
##   no  0.45174538 0.46776181
##   yes 0.04825462 0.03223819

Il est possible d’appliquer une fonction sur le tableau croisé ; par exemple, on peut vouloir appliquer la fonction round() pour afficher moins de décimales :

table(call = resumes$call, ethnicity = resumes$ethnicity) %>% 
  prop.table() %>% 
  round(digits = 2)
##      ethnicity
## call  cauc afam
##   no  0.45 0.47
##   yes 0.05 0.03

Les proportions marginales peuvent être obtenues en précisant l’argument margin à la fonction prop.table(). En optant pour margin = 1, on obtient les fréquences relatives à chaque ligne (ici, on peut lire la fréquence marginale des ethnicités selon la réponse obtenue ou non) :

table(call = resumes$call, ethnicity = resumes$ethnicity) %>% 
  prop.table(margin = 1) %>% 
  round(2)
##      ethnicity
## call  cauc afam
##   no  0.49 0.51
##   yes 0.60 0.40

En optant pour margin = 2, on obtient les fréquences relatives à chaque colonne (ici, on peut lire la fréquence marginale des réponses selon l’ethnicité, ce qui est particulièrement intéressant dans la question posée par le papier de recherche) :

table(call = resumes$call, ethnicity = resumes$ethnicity) %>% 
  prop.table(margin = 2) %>% 
  round(digits = 2)
##      ethnicity
## call  cauc afam
##   no  0.90 0.94
##   yes 0.10 0.06

Exercice

Dans une expérience aléatoire, pour mesurer l’effet d’un traitement, il est important de s’assurer du côté aléatoire du traitement. Si on veut mesurer l’effet de l’ethnicité sur la probabilité d’être contacté lorsque l’on postule à une offre d’emploi, et que l’on veut aussi mesurer l’effet du genre sur cette probabilité, il est important que le genre et l’ethnicité ne soient pas des caractéristiques liées. On doit donc créer l’expérience de sorte que la proportion de CVs de femmes et d’hommes soit statistiquement identique selon que la personne soit afro-américaine ou caucasienne.

  1. Affichez la proportion de femmes et d’hommes dans le jeu de données resumes.
  2. Idem avec la proportion d’afro-américains et de caucasiens.
  3. Affichez un tableau croisé montant les fréquences de femems et d’hommes selon l’ethnicité.
  4. Affichez ensuite les fréquences marginales permettant de penser que l’ethnicité et le genre ne sont pas liés dans l’expérience.

Dans le cours de Statistiques Inférentielles de 2e année, vous avez appris à effectuer un test d’indépendance à l’aide d’une statistique du Khi-deux.

effectifs_obs <- table(call = resumes$call, ethnicity = resumes$ethnicity) 

prop_table <- 
  effectifs_obs %>% 
  prop.table(margin = 2)
prop_table
##      ethnicity
## call        cauc       afam
##   no  0.90349076 0.93552361
##   yes 0.09650924 0.06447639

Avec ce tableau croisé, on lit que 9,6% des CV de personnes caucasiennes ont obtenu une réponse, tandis que seulement 6,4% des CV de personnes afro-américaines en ont obtenu une. Cette différence de 3,2% est-elle due au hasard ? Sous l’hypothèse nulle du test de Khi-deux, on s’attend à ce que les proportions soient identiques, indépendamment de l’origine ethnique. Si nous rejetons l’hypothèse nulle de ce test, nous serons amenés à penser que la différence de3,2% observée n’est pas due au hasard ; autrement dit, nous pourrons conclure, avec un risque de première espèce donné, que le taux de réponses suite à une candidature pour un emploi à Boston et Chicago est dépendant de l’ethnicité (et qu’il y a donc de la discrimination).

La statistique du test est la suivante :

\[\chi^2 = \sum_{j=1}^{q} \sum_{i=1}^{p} \frac{(n_{ij} - n_{ij}^e)^2}{n_{ij}^e},\]

avec \(q\) le nombre de sous-populations (ici, \(q=2\) : afro-américains et caucasiens) et \(p\) le nombre de modalités du caractère étudié (ici, \(p=2\) : rappel ou non), \(n_{ij}\) le nombre obseré d’observations dans la sous-population \(j\) disposant du caractère \(i\) et \(n_{ij}^e\) le nombre d’observations théoriques que l’on s’attend à observer dans la sous-population \(j\) avec le caractère \(i\) si l’hypothèse nulle est vraie.

Les effectifs observés sont les suivants :

effectifs_obs
##      ethnicity
## call  cauc afam
##   no  2200 2278
##   yes  235  157

Si l’etnicité est indépendante du fait de se faire rappeler suite à un dépot de CV, alors on s’attend aux valeurs suivantes :

# caucasien & pas de rappel
(2200+235) * (2200+2278) / sum(effectifs_obs)
## [1] 2239
# caucasien et rappel
(2200+235) * (235+157) / sum(effectifs_obs)
## [1] 196
# afro-américain & pas de rappel
(2278 + 157) * (2200+2278) / sum(effectifs_obs)
## [1] 2239
# afro-américain & rappel
(2278 + 157) * (235+157) / sum(effectifs_obs)
## [1] 196

On peut obtenir ces effectifs théoriques sans entrer à la main une seule valeur :

# Effectifs selon le caractère (rappelé ou non)
somme_ligne <- rowSums(effectifs_obs)
somme_ligne
##   no  yes 
## 4478  392
# Effectifs selon les sous-populations (afam ou cauc)
somme_colonne <- colSums(effectifs_obs)
somme_colonne
## cauc afam 
## 2435 2435
# Nombre total d'observations
n <- sum(effectifs_obs)
n
## [1] 4870

Reste alors à calculer le produit extérieur (on multiplie chaque élément du vecteur somme_ligne par chaque élément du vecteur somme_colonne), puis à diviser par l’effectif total :

effectifs_theo <- outer(somme_ligne, somme_colonne, "*")/n
effectifs_theo
##     cauc afam
## no  2239 2239
## yes  196  196

On peut de fait calculer la statistique de test :

statstique <- sum((effectifs_obs - effectifs_theo)^2 / effectifs_theo)
statstique
## [1] 16.87905

Cette statistique est à comparer avec le quantile d’ordre \(\alpha\), \(\chi^{2, \alpha}_{(p-1)(q-1)}\) que l’on peut lire dans une table du Khi-deux à \((p-1)(q-1)\) degrés de liberté… ou que l’on peut obtenir avec R ! La fonction qchisq() permet d’obtenir le quantile \(\chi^{2, \alpha}_{(p-1)(q-1)}\) tel que la probabilité d’obtenir une valeur supérieure à ce quantile selon une Khi-deux à \((p-1)(q-1)\) degrés de liberté soit égale à \(1-\alpha\).

alpha = 5/100
p <- 2 ; q <- 2
qchisq(p = 1-alpha, df = (p-1)*(q-1))
## [1] 3.841459

La statistique observée étant largement supérieure au quantile obtenu, on rejette l’hypothèse nulle du test (avec un risque de rejetter l’hypothèse nulle à tort de 5%) d’indépendance de l’ethnicité et de la réponse à une candidature à Boston ou Chicago. Il semble bien qu’il y ait une discrimination à l’accès à l’emploi.

On peut également calculer la probabilité d’observer une valeur au moins aussi grande que celle que nous observons pour notre statistique (16.88) : c’est-à-dire, chercher à calculer la p-value associée au test. La fonction pchisq() nous donne la probailité d’observer une valeur inférieure ou égale à un quantile donné, pour un degré de liberté spécifique. Aussi, ce que nous recherchons est 1 moins cette probabilité :

1-pchisq(q = statstique, df = (p-1)*(q-1))
## [1] 3.983887e-05

Cette p-value est très faible. Grossièrement parlant, il y a une probabilité de \(3,98\times 10^{-5}\) d’observer une valeur de la statistique du test qui soit au moins aussi grande que 16.87, si l’hypothèse nulle du test est vraie.

Rassurez-vous, pour effectuer un test du Khi-deux, il n’est pas nécessaire de passer par toutes ces étapes avec R. Il existe évidemment une fonction qui vous permette d’effectuer le test en une seule ligne, à partir du moment où vous avez obtenu votre tableau croisé : chisq.test(). On retrouve bien les mêmes valeurs.

res <- chisq.test(effectifs_obs, correct = FALSE)
res
## 
##  Pearson's Chi-squared test
## 
## data:  effectifs_obs
## X-squared = 16.879, df = 1, p-value = 3.984e-05
res$statistic
## X-squared 
##  16.87905
res$parameter
## df 
##  1
res$p.value
## [1] 3.983887e-05

Note : Par défaut, l’argument correct de la fonction chisq.test() vaut TRUE. Dans ce cas, la correction de continuité de Yates est appliquée. La statistique de test est alors légèrment modifiée :

\[\chi^2 = \sum_{j=1}^{q} \sum_{i=1}^{p} \frac{\left(\left\vert n_{ij} - n_{ij}^e \right\vert - 0,5\right)^2}{n_{ij}^e}.\]

7.2.2.2 Statistiques par sous-groupes

Pour obtenir le même type d’informations que ce qui est offert par la fonction table(), nous pouvons effectuer dans un premier temps un regroupement du tableau de données avec la fonction group_by() que nous avons déjà utilisée dans le chapitre portant sur les tableaux de données. Ensuite, en appliquant la fonction count() au résultat, nous pouvons obtenir les fréquence pour chacun des sous-groupes.

resumes %>% 
  group_by(call, ethnicity) %>% 
  count()
## # A tibble: 4 × 3
## # Groups:   call, ethnicity [4]
##   call  ethnicity     n
##   <fct> <fct>     <int>
## 1 no    cauc       2200
## 2 no    afam       2278
## 3 yes   cauc        235
## 4 yes   afam        157

L’argument name de la fonction count() permet de spécifier le nom de la colonne dans laquelle les effectifs seront reportés :

resumes %>% 
  group_by(call, ethnicity) %>% 
  count(name = "Nombre d'observations")
## # A tibble: 4 × 3
## # Groups:   call, ethnicity [4]
##   call  ethnicity `Nombre d'observations`
##   <fct> <fct>                       <int>
## 1 no    cauc                         2200
## 2 no    afam                         2278
## 3 yes   cauc                          235
## 4 yes   afam                          157

On peut vérifier, à l’aide de la fonction filter() que le décompte correspond bien au nombre d’observations pour lesquelles la valeur dans la colonne call est "no" et pour lesquelles celles dans la colonne ethnicity vaut "cauc" :

resumes %>%
  filter(call == "no" & ethnicity == "cauc") %>%
  nrow()
## [1] 2200

Pour obtenir les fréquences marginales, il suffit d’effectuer un nouveau regroupement après l’appel à la fonction count() :

resumes %>% 
  group_by(call, ethnicity) %>% 
  count(name = "Nombre d'observations") %>% 
  group_by(ethnicity) %>% 
  mutate(prop = `Nombre d'observations` / sum(`Nombre d'observations`),
         prop = round(prop, 2))
## # A tibble: 4 × 4
## # Groups:   ethnicity [2]
##   call  ethnicity `Nombre d'observations`  prop
##   <fct> <fct>                       <int> <dbl>
## 1 no    cauc                         2200  0.9 
## 2 no    afam                         2278  0.94
## 3 yes   cauc                          235  0.1 
## 4 yes   afam                          157  0.06

Pour obtenir des résumés statistiques de variables numériques, on peut utiliser le combo group_by() et summarise() abordé dans le chapitre portant sur les tableaux de données :

resumes %>% 
  group_by(gender, ethnicity) %>% 
  summarise(mean_experience = mean(experience),
            sd_experience = sd(experience),
            q1_experience = quantile(experience, probs = .25))
## # A tibble: 4 × 5
## # Groups:   gender [2]
##   gender ethnicity mean_experience sd_experience q1_experience
##   <fct>  <fct>               <dbl>         <dbl>         <dbl>
## 1 male   cauc                 7.68          5.34             5
## 2 male   afam                 7.37          5.01             5
## 3 female cauc                 7.91          4.99             5
## 4 female afam                 7.96          5.00             5

Exercice

  1. Calculez le nombre d’observations pour chaque valeur différente de la colonne name du tableau resumes.
  2. Calculez les proportions de chaque valeur différente de la colonne name du tableau resumes.
  3. Calculez, pour chaque valeur différente de la colonne name, la proportion de réponses positives (call valant "yes"{R}) et de réponses négatives (call valant "no"{R}).
  4. Calculez le nombre d’emplois passés (colonne jobs) selon le nom et le genre (colonnes name et gender).

7.3 Résumés avec gtsummary : vers la communication des résultats

Les différentes méthodes abordées jusqu’à présent pour réaliser des résumés statistiques sont très pratiques pour réaliser une fouille grossière des données. Dans cette partie, nous allons explorer quelques possibilités offertes par un package nommé {gtsummary}, qui permet de produire des tableaux formatés pour être communiqués. Il existe de bien nombreux packages qui permettent de réaliser des tableaux prêts pour la communication, mais il me semble que {gtsummary} offre des fonctionnalités particulièrement utiles pour des économètres.

Dans un premier temps, si le package n’est pas installé :

install.packages(gtsummary)

Ensuite, chargons le package :

library(gtsummary)

La fonction au cœur du package se nomme tbl_summary(). Elle produit un tableau qui s’affiche dans l’onglet “Viewer”. Le tableau qui est produit s’adapte en fonction du contenu des colonnes : une détection automatique du type des variables est effectuée. Lorsque les variables sont discrètes, la colonne descriptive indique le nombre d’observation et la proportion que chaque modalité représente. Lorsque les variables sont continues, la description est la médiane et l’écart interquartile.

resumes %>%
  tbl_summary()
Characteristic N = 4,870
name
Allison 232 (4.8%)
Anne 242 (5.0%)
Carrie 168 (3.4%)
Emily 227 (4.7%)
Jill 203 (4.2%)
Laurie 195 (4.0%)
Kristen 213 (4.4%)
Meredith 187 (3.8%)
Sarah 193 (4.0%)
Brad 63 (1.3%)
Brendan 65 (1.3%)
Geoffrey 59 (1.2%)
Greg 51 (1.0%)
Brett 59 (1.2%)
Jay 67 (1.4%)
Matthew 67 (1.4%)
Neil 76 (1.6%)
Todd 68 (1.4%)
Aisha 180 (3.7%)
Ebony 208 (4.3%)
Keisha 183 (3.8%)
Kenya 196 (4.0%)
Lakisha 200 (4.1%)
Latonya 230 (4.7%)
Latoya 226 (4.6%)
Tamika 256 (5.3%)
Tanisha 207 (4.3%)
Darnell 42 (0.9%)
Hakim 55 (1.1%)
Jamal 61 (1.3%)
Jermaine 52 (1.1%)
Kareem 64 (1.3%)
Leroy 64 (1.3%)
Rasheed 67 (1.4%)
Tremayne 69 (1.4%)
Tyrone 75 (1.5%)
gender
male 1,124 (23%)
female 3,746 (77%)
ethnicity
cauc 2,435 (50%)
afam 2,435 (50%)
call 392 (8.0%)
city
boston 2,166 (44%)
chicago 2,704 (56%)
jobs
1 110 (2.3%)
2 704 (14%)
3 1,429 (29%)
4 1,611 (33%)
5 533 (11%)
6 464 (9.5%)
7 19 (0.4%)
experience 6 (5, 9)
1 n (%); Median (IQR)

Parmi les arguments de la fonction tbl_summary(), figure by= qui permet de réaliser des sous-groupes dans les données avant de reporter les statistiques descriptives. Les différents groupes sont alors créés en fonction des valeurs distinctes rencontrées dans le colonne dont le nom est indiqué à l’argument by=. Par exemple, pour obtenir des statistiques descriptives du jeu de données resumes selon l’origine ethnique (colonne ethnicity), on pourra écrire :

resumes %>%
  tbl_summary(by = ethnicity)
Characteristic cauc, N = 2,435 afam, N = 2,435
name
Allison 232 (9.5%) 0 (0%)
Anne 242 (9.9%) 0 (0%)
Carrie 168 (6.9%) 0 (0%)
Emily 227 (9.3%) 0 (0%)
Jill 203 (8.3%) 0 (0%)
Laurie 195 (8.0%) 0 (0%)
Kristen 213 (8.7%) 0 (0%)
Meredith 187 (7.7%) 0 (0%)
Sarah 193 (7.9%) 0 (0%)
Brad 63 (2.6%) 0 (0%)
Brendan 65 (2.7%) 0 (0%)
Geoffrey 59 (2.4%) 0 (0%)
Greg 51 (2.1%) 0 (0%)
Brett 59 (2.4%) 0 (0%)
Jay 67 (2.8%) 0 (0%)
Matthew 67 (2.8%) 0 (0%)
Neil 76 (3.1%) 0 (0%)
Todd 68 (2.8%) 0 (0%)
Aisha 0 (0%) 180 (7.4%)
Ebony 0 (0%) 208 (8.5%)
Keisha 0 (0%) 183 (7.5%)
Kenya 0 (0%) 196 (8.0%)
Lakisha 0 (0%) 200 (8.2%)
Latonya 0 (0%) 230 (9.4%)
Latoya 0 (0%) 226 (9.3%)
Tamika 0 (0%) 256 (11%)
Tanisha 0 (0%) 207 (8.5%)
Darnell 0 (0%) 42 (1.7%)
Hakim 0 (0%) 55 (2.3%)
Jamal 0 (0%) 61 (2.5%)
Jermaine 0 (0%) 52 (2.1%)
Kareem 0 (0%) 64 (2.6%)
Leroy 0 (0%) 64 (2.6%)
Rasheed 0 (0%) 67 (2.8%)
Tremayne 0 (0%) 69 (2.8%)
Tyrone 0 (0%) 75 (3.1%)
gender
male 575 (24%) 549 (23%)
female 1,860 (76%) 1,886 (77%)
call 235 (9.7%) 157 (6.4%)
city
boston 1,083 (44%) 1,083 (44%)
chicago 1,352 (56%) 1,352 (56%)
jobs
1 54 (2.2%) 56 (2.3%)
2 347 (14%) 357 (15%)
3 726 (30%) 703 (29%)
4 800 (33%) 811 (33%)
5 258 (11%) 275 (11%)
6 243 (10.0%) 221 (9.1%)
7 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9)
1 n (%); Median (IQR)

Pour la suite de cette section, nous allons éviter d’afficher les informations pour la colonne name, pour gagner un peu en lisibilité. Pour ce faire, il suffit d’exclure du tableau cette colonne avant d’appliquer la fonction tbl_summary :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity)
Characteristic cauc, N = 2,435 afam, N = 2,435
gender
male 575 (24%) 549 (23%)
female 1,860 (76%) 1,886 (77%)
call 235 (9.7%) 157 (6.4%)
city
boston 1,083 (44%) 1,083 (44%)
chicago 1,352 (56%) 1,352 (56%)
jobs
1 54 (2.2%) 56 (2.3%)
2 347 (14%) 357 (15%)
3 726 (30%) 703 (29%)
4 800 (33%) 811 (33%)
5 258 (11%) 275 (11%)
6 243 (10.0%) 221 (9.1%)
7 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9)
1 n (%); Median (IQR)

Pour réaliser un test d’indépendance entre chaque variables et la variable de regroupement, on peut appliquer la fonction add_p() sur le tableau gtsummary. Une colonne est ajoutée à droite avec les p-values.

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p()
Characteristic cauc, N = 2,435 afam, N = 2,435 p-value
gender 0.4
male 575 (24%) 549 (23%)
female 1,860 (76%) 1,886 (77%)
call 235 (9.7%) 157 (6.4%) <0.001
city >0.9
boston 1,083 (44%) 1,083 (44%)
chicago 1,352 (56%) 1,352 (56%)
jobs 0.7
1 54 (2.2%) 56 (2.3%)
2 347 (14%) 357 (15%)
3 726 (30%) 703 (29%)
4 800 (33%) 811 (33%)
5 258 (11%) 275 (11%)
6 243 (10.0%) 221 (9.1%)
7 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Avoir des statistiques pour chacun des sous groupes est très utile, mais il est parfois également intéressant d’afficher les statistiques pour l’échantillon total. Pour ce faire, on peut utiliser la fonction add_overall(), qui ajoutera une colonne à gauche. En fournissant à l’argument col_label= une chaîne de caractère, le nom de la colonne ainsi ajoutée peut être modifié (par défaut, la valeur "Overall" est utilisée) :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total")
Characteristic Overall, N = 4,870 cauc, N = 2,435 afam, N = 2,435 p-value
gender 0.4
male 1,124 (23%) 575 (24%) 549 (23%)
female 3,746 (77%) 1,860 (76%) 1,886 (77%)
call 392 (8.0%) 235 (9.7%) 157 (6.4%) <0.001
city >0.9
boston 2,166 (44%) 1,083 (44%) 1,083 (44%)
chicago 2,704 (56%) 1,352 (56%) 1,352 (56%)
jobs 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Sur la première colonne, on peut lire en cartouche : Characteristic. Pour changer cela, on peut faire appel à la fonction modify_header(), en indiquant la valeur souhaitée à l’argument label=. On peut fournir une valeur rédigée en markdown. Dans l’exemple ci-dessous, pour que la valeur Variable soit affichée, on écrit ainsi :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**")
Variable Overall, N = 4,870 cauc, N = 2,435 afam, N = 2,435 p-value
gender 0.4
male 1,124 (23%) 575 (24%) 549 (23%)
female 3,746 (77%) 1,860 (76%) 1,886 (77%)
call 392 (8.0%) 235 (9.7%) 157 (6.4%) <0.001
city >0.9
boston 2,166 (44%) 1,083 (44%) 1,083 (44%)
chicago 2,704 (56%) 1,352 (56%) 1,352 (56%)
jobs 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Pour ajouter une étiquette permettant de regrouper visuellement les sous-groupes, le package {gtsummary} propose la fonction modify_spanning_header(). Dans notre exemple, nous avons deux sous-groupes formés selon les modalités de la variable ethnicity. Aussi, nous pourrons indiquer que nous souhaitons que les colonnes stat_1 et stat_2 (colonne contenant les statistiques descriptives pour le premier et le second sous-groupes) disposent d’une en-tête :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 cauc, N = 2,435 afam, N = 2,435 p-value
gender 0.4
male 1,124 (23%) 575 (24%) 549 (23%)
female 3,746 (77%) 1,860 (76%) 1,886 (77%)
call 392 (8.0%) 235 (9.7%) 157 (6.4%) <0.001
city >0.9
boston 2,166 (44%) 1,083 (44%) 1,083 (44%)
chicago 2,704 (56%) 1,352 (56%) 1,352 (56%)
jobs 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
experience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Lorsque les colonnes du tableau de données fourni à la fonction tbl_summary() contient des étiquettes, ces dernières sont automatiquement utilisées dans le tableau retourné à la place des noms de variables. Pour ajouter des étiquettes à des colonnes, nous pouvons utiliser le package {labelled}, qu’il faut au préalable installer.

install.packages("labelled")

Une fois le package installé, il est nécessaire de le charger :

library(labelled)

La fonction set_variable_labels() de {labelled} permet d’ajouter les étiquettes aux variables. Il suffit de donner le nom des variables et, après un symbole égal (=), leur étiquette correspondante.

resumes <- 
  resumes %>% 
  labelled::set_variable_labels(
    name = "Prénom",
    gender = "Genre",
    ethnicity = "Ethnicité",
    call = "Entretien",
    city = "Ville",
    jobs = "Nombre d'emplois listés",
    experience = "Nombre d'années d'expérience"
  )

Si on évalue à nouveau notre dernier code permettant d’afficher un tableau de statistiques descriptives pour notre jeu de données, on note que les noms de variables (gender, call, city, etc.) ne s’affichent plus et qu’à la place, l’étiquette est utilisée :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 cauc, N = 2,435 afam, N = 2,435 p-value
Genre 0.4
male 1,124 (23%) 575 (24%) 549 (23%)
female 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien 392 (8.0%) 235 (9.7%) 157 (6.4%) <0.001
Ville >0.9
boston 2,166 (44%) 1,083 (44%) 1,083 (44%)
chicago 2,704 (56%) 1,352 (56%) 1,352 (56%)
Nombre d’emplois listés 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Note

Il est possible de fournir à l’argument label= de la fonction tbl_summary() les étiquettes à utiliser pour chaque variable, plutôt que de passer par la définition des étiquettes via l’ajout d’un attribut aux colonnes avec la fonction set_variable_labels().

Le nom des différents sous-groupes constitués à l’aide de la variable dont le nom est fourni à l’argument by= de la fonction tbl_summary() sont définis selon les valeurs présentes dans le tableau. Pour recoder les valeurs d’une variable factorielle, nous pouvons utiliser la fonction recode() de {dplyr}. Attention, la syntaxe est assez peu heureuse, dans la mesure où elle est à contre courant de ce que l’on peut trouver avec la fonction rename() (fonction permettant de renommer les colonnes d’un tableau de données) : on écrit l’ancien nomn, puis après un symbole égal (=) le nouveau nom, dans une chaîne de caractères.

resumes <- 
  resumes %>% 
  mutate(
    gender = recode(gender, female = "femme", male = "homme"),
    ethnicity = recode(ethnicity,
                       cauc = "Caucasien", afam = "Afro-americain"),
    call = recode(call, no = "Non", yes = "Oui")
  )

resumes
## # A tibble: 4,870 × 7
##    name    gender ethnicity      call  city     jobs experience
##    <fct>   <fct>  <fct>          <fct> <fct>   <int>      <int>
##  1 Allison femme  Caucasien      Non   chicago     2          6
##  2 Kristen femme  Caucasien      Non   chicago     3          6
##  3 Lakisha femme  Afro-americain Non   chicago     1          6
##  4 Latonya femme  Afro-americain Non   chicago     4          6
##  5 Carrie  femme  Caucasien      Non   chicago     3         22
##  6 Jay     homme  Caucasien      Non   chicago     2          6
##  7 Jill    femme  Caucasien      Non   chicago     2          5
##  8 Kenya   femme  Afro-americain Non   chicago     4         21
##  9 Latonya femme  Afro-americain Non   chicago     3          3
## 10 Tyrone  homme  Afro-americain Non   chicago     2          6
## # ℹ 4,860 more rows

Une fois les valeurs recodées à l’intérieur du tableau, celui qui est produit par la fonction tbl_summary() est également impacté :

resumes %>%
  select(-name) %>% 
  tbl_summary(by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Ville >0.9
boston 2,166 (44%) 1,083 (44%) 1,083 (44%)
chicago 2,704 (56%) 1,352 (56%) 1,352 (56%)
Nombre d’emplois listés 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Pour décider qulles variables inclure dans le tableau de statistiques descriptives, on peut utiliser la fonction select() de {dplyr} sur le tableau de l’on fournit à la fonction tbl_summary(), ou bien on peut préciser quelles colonnes inclure à l’aide de l’argument include= de tbl_summary().

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 6 (5, 9) 6 (5, 9) 6 (5, 9) 0.9
1 n (%); Median (IQR)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

L’argument statistic= de la fonction tbl_summary() permet de changer les statistiques reportées. On fournit une liste dans laquelle on indique des formules spécifiant les types de statistiques descriptives à afficher pour les variables. Nous avons vu plus haut que les valeurs par défaut qui sont utilisées sont la médiane, suivi, entre parenthèses de l’écart interquartile pour les variables continues, et le nombre d’observations suivi de la proportion entre parenthèses, soit :

list(all_continuous() ~ "{median} ({p25}, {p75})",
     all_categorical() ~ "{n} ({p}%)")

Si on désire afficher la moyenne (mean) suivie de l’écart-type (standard deviation) pour les variables continues, et le nombre d’observations et la proportion pour les variables discrètes, on écrira :

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    statistic = list(
      all_continuous() ~ "{mean} ({sd})",
      all_categorical() ~ "{n} ({p}%)"
      )
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 8 (5) 8 (5) 8 (5) 0.9
1 n (%); Mean (SD)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Pour afficher des résumés statistiques sur plusieurs lignes pour les variables continues, il faut le préciser, à l’aide de l’argument type= de la fonction tbl_summary(). En écrivant type = all_continuous() ~ "continuous2", toutes les variables continues disposeront de deux lignes de résumés statistiques. Reste alors à indiquer ce qu’indiquera chaque ligne. Pour cela, ils nous suffit de fournir un vecteur de longueur 2 à l’élément de la liste fournie au pramètre statistic= qui se charge de définir les statistiques à retourner pour les variables continues. Dans l’exemple qui suit, nous reporterons la moyenne et l’écart-type sur la première ligne, et la médiane accompagnée de l’écart interquartile sur la seconde.

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = all_continuous() ~ "continuous2",
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      )
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**")
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 0.9
Mean (SD) 8 (5) 8 (5) 8 (5)
Median (IQR) 6 (5, 9) 6 (5, 9) 6 (5, 9)
1 n (%)
2 Pearson’s Chi-squared test; Wilcoxon rank sum test

Avec la fonction add_stat_label(), nous pouvons préciser, en créant une liste contenant des formules, les indications à faire figurer dans le tableau pour les étiquettes des statistiques qui s’afficheront. Dans l’exemple qui suit, nous demandons à ce que sur la première ligne figure la valeur Moyenne (Ecart-type) et sur la deuxième Médiane (IQR) lorsque la variables est continue, et n (%) lorsqu’elle est discrète.

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = all_continuous() ~ "continuous2",
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      )
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés, n (%) 0.7
1 110 (2.3%) 54 (2.2%) 56 (2.3%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (9.5%) 243 (10.0%) 221 (9.1%)
7 19 (0.4%) 7 (0.3%) 12 (0.5%)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 8 (5) 8 (5) 8 (5)
Médiane (IQR) 6 (5, 9) 6 (5, 9) 6 (5, 9)
1 Pearson’s Chi-squared test; Wilcoxon rank sum test

Dans l’ensemble des tableaux que nous avons réalisés avec la fonction tbl_summary(), la variable jobs qui indique le nombre de précédents emplois occupés a été considérée comme étant discrète. Si nous souhaitons que la fonction considère cette colonne comme étant numérique, il faut l’indiquer à travers l’argument type, en donnant comme élément de liste une formule spécifique pour cette colonne :

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = list(all_continuous() ~ "continuous2",
                jobs ~ "continuous2"),
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      )
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés >0.9
Moyenne (Ecart-type) 4 (1) 4 (1) 4 (1)
Médiane (IQR) 4 (3, 4) 4 (3, 4) 4 (3, 4)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 8 (5) 8 (5) 8 (5)
Médiane (IQR) 6 (5, 9) 6 (5, 9) 6 (5, 9)
1 Pearson’s Chi-squared test; Wilcoxon rank sum test

Le contrôle du nombre de chiffres après la virgule s’effectue via l’argument digits. Encore une fois, une liste contenant des formules est donnée. Ici, demandons d’afficher 3 décimales après la virgule pour chaque statistique des variables continues :

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = list(all_continuous() ~ "continuous2",
                jobs ~ "continuous2"),
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      ),
    digits = list(all_continuous() ~ 3)
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés >0.9
Moyenne (Ecart-type) 3.661 (1.219) 3.664 (1.219) 3.658 (1.219)
Médiane (IQR) 4.000 (3.000, 4.000) 4.000 (3.000, 4.000) 4.000 (3.000, 4.000)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 7.843 (5.045) 7.856 (5.079) 7.830 (5.011)
Médiane (IQR) 6.000 (5.000, 9.000) 6.000 (5.000, 9.000) 6.000 (5.000, 9.000)
1 Pearson’s Chi-squared test; Wilcoxon rank sum test

Lorsque de multiples statistiques sont retournées pour une variable, on fournit un vecteur de valeurs à la formule si on désire que le nombre de décimales soit différent d’une statistique à l’autre. La longueur de ce vecteur doit correspondre au nombre de statistiques demandées via l’argument statistic=. Ici, demandons d’afficher 1 décimale pour la moyenne, 3 pour l’écart-type et la médiane, puis 1 pour les premiers et troisièmes quartiles.

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = list(all_continuous() ~ "continuous2",
                jobs ~ "continuous2"),
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      ),
    digits = list(all_continuous() ~ c(1,3, 3,1,1))
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés >0.9
Moyenne (Ecart-type) 3.7 (1.219) 3.7 (1.219) 3.7 (1.219)
Médiane (IQR) 4.000 (3.0, 4.0) 4.000 (3.0, 4.0) 4.000 (3.0, 4.0)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 7.8 (5.045) 7.9 (5.079) 7.8 (5.011)
Médiane (IQR) 6.000 (5.0, 9.0) 6.000 (5.0, 9.0) 6.000 (5.0, 9.0)
1 Pearson’s Chi-squared test; Wilcoxon rank sum test

Il est également possible de définir le nombre de décimales spécifiquement pour une ou plusieurs variables, en ajoutant une ou plusieurs formules à la liste fournie à l’argument digits= de la fonction tbl_summary().

resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = list(all_continuous() ~ "continuous2",
                jobs ~ "continuous2"),
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"
      ),
    digits = list(all_continuous() ~ c(1,3, 3,1,1),
                  jobs ~ c(0, 0, 0, 0, 0))
    ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label = "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Overall, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-value
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8.0%) 235 (9.7%) 157 (6.4%)
Nombre d’emplois listés >0.9
Moyenne (Ecart-type) 4 (1) 4 (1) 4 (1)
Médiane (IQR) 4 (3, 4) 4 (3, 4) 4 (3, 4)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 7.8 (5.045) 7.9 (5.079) 7.8 (5.011)
Médiane (IQR) 6.000 (5.0, 9.0) 6.000 (5.0, 9.0) 6.000 (5.0, 9.0)
1 Pearson’s Chi-squared test; Wilcoxon rank sum test

Les tableaux produits utilisent par défaut des normes anglo-saxonnes. Pour utiliser des normes françaises, on peut se servir de la fonction theme_gtsummary_language() et indiquer la valeur "fr" à l’argument language= :

theme_gtsummary_language(language = "fr")
resumes %>%
  tbl_summary(
    include = c("gender", "ethnicity", "call", "jobs", "experience"),
    by = ethnicity,
    type = all_continuous() ~ "continuous2",
    statistic = list(
      all_continuous() ~ c("{mean} ({sd})", "{median} ({p25}, {p75})"),
      all_categorical() ~ "{n} ({p}%)"),
    digits = list(
      all_continuous() ~ 2,
      all_categorical() ~ 0
    )
  ) %>% 
  add_p() %>% 
  add_overall(col_label = "Ech. total") %>% 
  modify_header(label ~ "**Variable**") %>% 
  modify_spanning_header(c("stat_1", "stat_2") ~ "**Consonnance du nom**") %>% 
  add_stat_label(
    label = list(
      all_continuous() ~ c("Moyenne (Ecart-type)", "Médiane (IQR)"),
      all_categorical() ~ "n (%)"
    )
  )
Consonnance du nom
Variable Total, N = 4,870 Caucasien, N = 2,435 Afro-americain, N = 2,435 p-valeur
Genre, n (%) 0.4
homme 1,124 (23%) 575 (24%) 549 (23%)
femme 3,746 (77%) 1,860 (76%) 1,886 (77%)
Entretien, n (%) <0.001
Non 4,478 (92%) 2,200 (90%) 2,278 (94%)
Oui 392 (8%) 235 (10%) 157 (6%)
Nombre d’emplois listés, n (%) 0.7
1 110 (2%) 54 (2%) 56 (2%)
2 704 (14%) 347 (14%) 357 (15%)
3 1,429 (29%) 726 (30%) 703 (29%)
4 1,611 (33%) 800 (33%) 811 (33%)
5 533 (11%) 258 (11%) 275 (11%)
6 464 (10%) 243 (10%) 221 (9%)
7 19 (0%) 7 (0%) 12 (0%)
Nombre d’années d’expérience 0.9
Moyenne (Ecart-type) 7.84 (5.04) 7.86 (5.08) 7.83 (5.01)
Médiane (IQR) 6.00 (5.00, 9.00) 6.00 (5.00, 9.00) 6.00 (5.00, 9.00)
1 test du khi-deux d’indépendance; test de Wilcoxon-Mann-Whitney

References

Bertrand, Marianne, and Sendhil Mullainathan. 2004. “Are Emily and Greg More Employable Than Lakisha and Jamal? A Field Experiment on Labor Market Discrimination.” American Economic Review 94 (4): 991–1013. https://doi.org/10.1257/0002828042002561.