21  Questions à réponses multiples

Dans certaines enquêtes, il est fréquent que certaines questions à choix multiples autorisent plusieurs réponses possibles. Ces questions ne peuvent être analysées de la même manière que les questions à réponse unique et nécessitent quelques ajustements.

La manière la plus simple de coder une question à réponse multiple est de coder chaque réponse sous la forme d’une variable binaire (oui/non).

21.1 Données de l’exemple

Prenons un exemple avec les données de l’enquête Histoire de vie 2003. L’une des questions portait sur les loisirs et était formulée ainsi : En dehors du cadre scolaire ou professionnel, au cours des 12 derniers mois, avez-vous pratiqué alors que vous n’y étiez pas obligé(e), les activités suivantes ?. Les enquêtés pouvaient sélectionner plusieurs options possibles.

library(tidyverse)
library(labelled)
data("hdv2003", package = "questionr")
d <- hdv2003 |> 
  set_variable_labels(
    hard.rock = "Écouter du hard rock",
    lecture.bd = "Lire des bandes dessinées",
    peche.chasse = "Aller à la pêche ou à la chasse",
    cuisine = "Faire la cuisine",
    bricol = "Bricoler",
    cinema = "Aller au cinéma",
    sport = "Pratiquer un sport"
  )
d |> 
  select(hard.rock:sport) |> 
  look_for()
 pos variable     label                           col_type missing values
 1   hard.rock    Écouter du hard rock            fct      0       Non   
                                                                   Oui   
 2   lecture.bd   Lire des bandes dessinées       fct      0       Non   
                                                                   Oui   
 3   peche.chasse Aller à la pêche ou à la chasse fct      0       Non   
                                                                   Oui   
 4   cuisine      Faire la cuisine                fct      0       Non   
                                                                   Oui   
 5   bricol       Bricoler                        fct      0       Non   
                                                                   Oui   
 6   cinema       Aller au cinéma                 fct      0       Non   
                                                                   Oui   
 7   sport        Pratiquer un sport              fct      0       Non   
                                                                   Oui   

Comme nous pouvons le voir, dans notre jeu de données, chaque réponse est codée sous la forme d’un facteur avec deux valeurs possibles : "Oui" et "Non".

21.2 Considérer chaque réponse indépendamment

Une première approche consiste à considérer chaque réponse indépendamment, en tant que variable binaire. On va ainsi calculer la proportion de répondants déclarant faire la cuisine ou faire du sport.

Pour alléger le tableau, nous allons déclarer chaque variable comme étant dichotomiques (dichotomous) afin de n’afficher que la proportion de Oui. Pour cela, avec gtsummary::tbl_summary(), nous allons utiliser l’argument type pour indiquer le type des variables et value pour indiquer la valeur correspondant à une réponse positive.

library(gtsummary)
theme_gtsummary_language("fr", decimal.mark = ",")
Setting theme "language: fr"
d |> 
  tbl_summary(
    include = hard.rock:sport,
    value = everything() ~ "Oui",
    type = everything() ~ "dichotomous",
    statistic = all_categorical() ~ "{p}% ({n})",
    digits = all_categorical() ~ c(p = 1, n = 0)
  )
Caractéristique N = 2 0001
Écouter du hard rock 0,7% (14)
Lire des bandes dessinées 2,4% (47)
Aller à la pêche ou à la chasse 11,2% (224)
Faire la cuisine 44,1% (881)
Bricoler 42,7% (853)
Aller au cinéma 41,3% (826)
Pratiquer un sport 36,2% (723)
1
Table 21.1: Proportion de participants pratiquant certains loisirs

Pour une représentation graphique, le plus simple reste un graphique en barres. Pour se faciliter la vie, on pourra profiter de la fonction guideR::plot_multiple_answers() du package guideR, le compagnon de guide-R.

library(guideR)
d |> 
  plot_multiple_answers(
    hard.rock:sport,
    value = "Oui",
    sort = "descending",
    fill = "#4477AA",
    flip = TRUE
  )
Figure 21.1: Proportion de participants pratiquant certains loisirs

Il est possible de comparer assez facilement les réponses selon une autre variable catégorielle, par exemple le sexe des répondants.

library(guideR)
d |> 
  plot_multiple_answers(
    hard.rock:sport,
    value = "Oui",
    by = sexe,
    sort = "descending",
    mapping = aes(fill = sexe),
    show.legend = FALSE,
    flip = TRUE
  ) +
  khroma::scale_fill_bright()
Figure 21.2: Proportion de participants pratiquant certains loisirs selon leur sexe

Une représentation alternative consiste à utiliser des barres décalées (dodged bars). Pour cela, nous allons utiliser guideR::plot_multiple_answers_dodge().

d |> 
  plot_multiple_answers_dodge(
    hard.rock:sport,
    value = "Oui",
    by = sexe,
    sort = "ascending",
    flip = TRUE
  ) +
  khroma::scale_fill_bright()
Figure 21.3: Proportion de participants pratiquant certains loisirs selon leur sexe (dodge)

Pour un tableau, il suffit d’utiliser l’argument by de gtsummary::tbl_summary(). Il est également possible de calculer des p-valeurs avec gtsummary::add_p().

d |> 
  tbl_summary(
    include = hard.rock:sport,
    by = sexe,
    value = everything() ~ "Oui",
    type = everything() ~ "dichotomous",
    statistic = all_categorical() ~ "{p}% ({n})",
    digits = all_categorical() ~ c(p = 1, n = 0)
  ) |> 
  add_overall(last = TRUE) |> 
  add_p() |> 
  bold_p()
Caractéristique Homme
N = 8991
Femme
N = 1 1011
Total
N = 2 0001
p-valeur2
Écouter du hard rock 0,8% (7) 0,6% (7) 0,7% (14) 0,7
Lire des bandes dessinées 1,7% (15) 2,9% (32) 2,4% (47) 0,069
Aller à la pêche ou à la chasse 19,1% (172) 4,7% (52) 11,2% (224) <0,001
Faire la cuisine 30,0% (270) 55,5% (611) 44,1% (881) <0,001
Bricoler 57,3% (515) 30,7% (338) 42,7% (853) <0,001
Aller au cinéma 39,7% (357) 42,6% (469) 41,3% (826) 0,2
Pratiquer un sport 41,0% (369) 32,2% (354) 36,2% (723) <0,001
1
2 test du khi-deux d’indépendance
Table 21.2: Proportion de participants pratiquant certains loisirs selon le sexe

21.3 Combiner les différentes réponses

Une autre approche consiste à combiner entre elles les différentes réponses et de calculer la proportion de chaque combinaison.

Pour une version graphique avec guideR::plot_multiple_answers(), il suffit juste de préciser combine_answers = TRUE. Attention : le nombre de combinaisons peut vite devenir très important. Ici, pour alléger la figure, nous nous limiterons à quatre activités uniquement. Il est possible là encore d’ajouter une variable de croisement. Pour faciliter la lecture, quand flip = FALSE, les réponses sont représentées sous la forme d’une matrice garce au package ggupset.

d |> 
  plot_multiple_answers(
    cuisine:sport,
    value = "Oui",
    combine_answers = TRUE,
    fill = "#4477AA",
    sort = "degrees"
  )
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
ℹ Please use `linewidth` instead.
ℹ The deprecated feature was likely used in the ggupset package.
  Please report the issue at <https://github.com/const-ae/ggupset/issues>.
d |> 
  plot_multiple_answers_dodge(
    cuisine:sport,
    value = "Oui",
    by = sexe,
    combine_answers = TRUE,
    sort = "degrees",
    show_labels = FALSE
  ) +
  khroma::scale_fill_bright()
Figure 21.4: Proportion de participants pratiquant certains loisirs
Figure 21.5: Proportion de participants pratiquant certains loisirs

Pour un tableau, on utilisera guideR::combine_answers() pour créer une nouvelle variable combinant les différentes réponses. Cette variable pourra ensuite être utilisée avec gtsummary::tbl_summary(). À noter, lorsqu’aucune réponse n’a été choisie, guideR::combine_answers() renvoie une chaîne de caractère vide. Nous allons donc recoder en "Aucun".

d <-
  d |> 
  combine_answers(
    cuisine:sport,
    value = "Oui",
    into = "loisirs",
    sep = ", "
  ) |> 
  mutate(
    loisirs = loisirs |>
      recode_if(loisirs == "", "Aucun")
  ) |> 
  set_variable_labels(
    loisirs = "Loisirs (12 derniers mois)"
  )
d |> 
  tbl_summary(
    include = loisirs,
    by = sexe,
    statistic = all_categorical() ~ "{p}% ({n})",
    digits = all_categorical() ~ c(p = 1, n = 0),
    sort = all_categorical() ~ "frequency"
  ) |> 
  add_overall(last = TRUE) |> 
  add_p() |> 
  bold_labels()
Caractéristique Homme
N = 8991
Femme
N = 1 1011
Total
N = 2 0001
p-valeur2
Loisirs (12 derniers mois)


<0,001
    Aucun 17,6% (158) 18,9% (208) 18,3% (366)
    Faire la cuisine 3,8% (34) 17,1% (188) 11,1% (222)
    Bricoler 16,8% (151) 3,4% (37) 9,4% (188)
    Faire la cuisine, Bricoler, Aller au cinéma, Pratiquer un sport 8,1% (73) 6,6% (73) 7,3% (146)
    Faire la cuisine, Bricoler 6,2% (56) 6,5% (72) 6,4% (128)
    Aller au cinéma 4,9% (44) 7,2% (79) 6,2% (123)
    Aller au cinéma, Pratiquer un sport 6,6% (59) 4,7% (52) 5,6% (111)
    Bricoler, Aller au cinéma, Pratiquer un sport 7,8% (70) 3,0% (33) 5,2% (103)
    Faire la cuisine, Aller au cinéma, Pratiquer un sport 2,7% (24) 6,3% (69) 4,7% (93)
    Faire la cuisine, Aller au cinéma 1,6% (14) 7,0% (77) 4,6% (91)
    Bricoler, Aller au cinéma 5,3% (48) 3,1% (34) 4,1% (82)
    Pratiquer un sport 4,6% (41) 3,7% (41) 4,1% (82)
    Faire la cuisine, Bricoler, Aller au cinéma 2,8% (25) 4,7% (52) 3,9% (77)
    Faire la cuisine, Bricoler, Pratiquer un sport 3,8% (34) 2,8% (31) 3,3% (65)
    Bricoler, Pratiquer un sport 6,5% (58) 0,5% (6) 3,2% (64)
    Faire la cuisine, Pratiquer un sport 1,1% (10) 4,5% (49) 3,0% (59)
1
2 test du khi-deux d’indépendance
Table 21.3: Proportion de participants pratiquant certains loisirs selon le sexe
Note

Lorsque l’on ne fournit pas d’option sep à guideR::combine_answers(), la fonction créé une colonne de type liste. C’est un format un peu particulier, mais cela permet quelques manipulations avancées, comme le calcul du nombre de réponses positives.

d <-
  d |> 
  combine_answers(
    cuisine:sport,
    value = "Oui",
    into = "liste_loisirs"
  ) |> 
  mutate(
    nb_loisirs = purrr::map(liste_loisirs, length) |> unlist()
  )
d |> 
  select(liste_loisirs, nb_loisirs) |> 
  glimpse()
Rows: 2,000
Columns: 2
$ liste_loisirs <list> "Faire la cuisine", <"Aller au cinéma", "Pratiquer un s…
$ nb_loisirs    <int> 1, 2, 1, 4, 0, 2, 1, 2, 1, 2, 3, 2, 1, 2, 2, 1, 4, 4, 0,…

21.4 Point sur les valeurs manquantes

Comme pour toute analyse, il est indispensable de bien vérifier en amont la présence de valeurs manquantes, par exemple avec questionr::freq.na().

hdv2003 |>
  select(hard.rock:sport) |>
  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

Dans notre exemple, cela n’est pas un enjeu.

En cas de présence de valeurs manquantes, il faut vérifier si elles sont cohérentes. En effet, si les données sont propres et la saisie cohérente, normalement une même observation devrait être manquante pour chaque sous-réponse ou pour aucune.

Selon les cas, on peut être amené à recoder certaines valeurs manquantes comme une réponse négative, ou bien exclure toute observation dont au moins une réponse est manquante.

Pour le second cas, on pourra, en amont de gtsummary::tbl_summary(), avoir recours à tidyr::drop_na() qui permet d’exclure toute observation incomplète. Par exemple :

hdv2003 |> 
  drop_na(hard.rock:sport) |> 
  tbl_summary(...)

Avec guideR::plot_multiple_answers(), il suffit d’utiliser l’option drop_na = TRUE.

hdv2003 |> 
  plot_multiple_answers(
    hard.rock:sport,
    drop_na = TRUE
  )