
Désagréger des choix multiples créés avec Google Forms
Pour ceux/celles qui ont eu la mauvaise idée de créer un questionnaire avec Google Forms [1], vous êtes confronté-es au problème que les choix multiples sont codés dans une seule colonne, comme une chaîne de caractères dont chacune des modalités de réponse sélectionnées sont séparées par un séparateur (" ;" ou ","). Cette variable n’est pas manipulable par les logiciels de statistiques. Je propose ici un script tout simple pour "désagréger" cette unique colonne en autant de variables dichotomiques qu’il y a de modalités de réponses.
Dans Google Forms, les choix multiples sont codés dans une seule colonne, comme une chaîne de caractères dont chacune des modalités de réponse sélectionnées sont séparées par un séparateur. Par exemple, à la question posée à des étudiant-es :
Google produit comme output cette structuration :
ID | Choix_multiple |
---|---|
1 | Apports_familiaux ;Économie_été |
2 | |
3 | Apports_familiaux |
4 | Aide_sociale_CPAS ;Job_année |
Or, pour pouvoir être manipulées dans un logiciel de statistiques, les variables doivent prendre la forme d’autant de variables dichotomiques qu’il y a de modalités de réponses dans le choix multiple.
Solution où les valeurs manquantes sont des 0
Voici une première forme qui est manipulable : chaque modalité de réponse est devenue une colonne, indiquant "1" si la case du choix multiple a été cochée et "0" dans le cas inverse. Dans cette forme, les cellules vides (rien n’a été coché, comme la ligne 2) deviennent des "0" sur toutes les nouvelles colonnes :
ID | Apports_familiaux | Économie_été | Job_année | Aide_sociale_ULB | Aide_sociale_CPAS | Chomage |
---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | 0 | 0 | 0 | 0 | 0 | 0 |
3 | 1 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 1 | 0 | 1 | 0 |
Voici une manière simple de passer vers cette forme avec R avec le tidyverse. Disons que la base de données qui contient la colonne a désagréger se nomme data.
Indiquez d’abord le numéro de colonne issue du choix multiple à désagréger, et quel séparateur est utilisé (ici " ;") :
library(tidyverse)
# Indiquer le numéro de la colonne à désagréger (on peut repérer le numéro avec view())
nb_col_to_split <- 12
# Indiquez le charactère séparateur qui sépare les réponses du choix multiple (";" par défaut dans Google Forms)
separator <- ";"
Le bout de code ci-dessous duplique ensuite la colonne sélectionnée en une colonne multichoice_forms qui est alors désagrégée. L’opération consiste à multiplier les lignes par le nombre de réponse du choix multiple avec separate_rows(), et d’ensuite de ré-agréger par individu, mais vers des colonnes différentes, avec pivot_wider(). Le tout est stocké dans un nouveau dataframe data_wider :
data$multichoice_forms <- data[,nb_col_to_split]
# Je transforme la variable du choix multiple en une multitude de colonnes
data_wider <- data %>%
separate_rows(multichoice_forms, sep = separator) %>% # je multiplie les lignes selon le nombre de réponses au choix multiple par individu (les mêmes individus sont donc dupliqués => voir de visu en arrêtant l'opération ici)
mutate(Value = 1) %>% # Je crée une valeur qui indique qu'il y a une réponse à la ligne
pivot_wider(names_from = multichoice_forms,
values_from = Value,
values_fill = 0) # J'aggrège avec pivot_wider() en remplissant d'un 0 lorsqu'il y a une valeur manquante
La procédure crée une colonne NA dont la valeur est "1" pour les répondant-es qui n’ont rien sélectionné au choix multiple. Cette colonne est redondante, puisqu’en cas de non-réponse au choix multiple (aucune modalité sélectionnée), toutes les nouvelles colonnes créées contiennent un "0". Il est donc utile de la supprimer, dans le cas où elle existe (il est en effet possible qu’il n’y ait aucune non-réponse). Le script si dessous supprime ainsi la dernière colonne si et seulement si celle-ci est une colonne NA .
# J'enlève la colonne de NA créée par la procédure à la fin du dataframa SSI cette variable existe
if (last(names(data_wider)) == "NA") { # Condition pour savoir si la dernière colonne s'apelle "NA"
data_wider <- data_wider %>%
select(-ncol(data_wider)) # Si oui, alors je supprime la dernière colonne (puisqu'on a vérifié que c'était bien "NA")
}
Il est également utile de vérifier que l’opération a fonctionné, en comparant la colonne de départ et les nouvelles colonnes créées. Le code ci-dessous ne sélectionne que ces colonnes et les exportes dans un CSV pour vérifier que l’opération s’est déroulée correctement.
# On crée un objet "verif" pour vérifier que la procédure a bien fonctionné
verif <- data_wider %>%
select(nb_col_to_split, ncol(data):ncol(data_wider))
# On écrit la vérification dans un fichier CSV
write.csv2(verif, file = "verif.csv")
Et voilà !
Solution où les valeurs manquantes sont des NA
Mais il est envisageable que nous désirions que les champs vides ne donnent pas lieu à des lignes de "0", mais de valeurs manquantes "NA" : il est probable qu’une personne qui n’a rien coché constitue une réponse manquante plutôt que l’indication qu’elle ne se reconnait dans aucune des modalités présentées. Nous voudrions alors obtenir un tableau de cette forme :
ID | Apports_familiaux | Économie_été | Job_année | Aide_sociale_ULB | Aide_sociale_CPAS | Chomage |
---|---|---|---|---|---|---|
1 | 1 | 1 | 0 | 0 | 0 | 0 |
2 | NA | NA | NA | NA | NA | NA |
3 | 1 | 0 | 0 | 0 | 0 | 0 |
4 | 0 | 0 | 1 | 0 | 1 | 0 |
Voici le code qui permet d’obtenir ce résultat. La base de données qui contient la colonne a désagréger se nomme maintenant data_NA.
Comme précédemment, indiquez d’abord le numéro de colonne issue du choix multiple à désagréger, et quel séparateur est utilisé (ici " ;") :
library(tidyverse)
# Indiquer le numéro de la colonne à désagréger (on peut repérer le numéro avec view())
nb_col_to_split <- 12
# Indiquez le charactère séparateur qui sépare les réponses du choix multiple (";" par défaut dans Google Forms)
separator <- ";"
L’opération consiste toujours à multiplier les lignes par le nombre de réponses du choix multiple, mais cette fois en bypassant les valeurs manquantes sur la variable à désagréger. Pour ce faire, on transforme au préalable les valeurs manquantes "NA" en un champs vide "". On crée également un identifiant unique par individu, nous verrons pourquoi.
Comme précédemment, la colonne à désagréger est dupliquée en une colonne multichoice_forms. On utilise alors les fonctions strsplit() et unnest() qui rendent possible la séparation des différentes réponses sur différentes lignes - mais sans les champs vides (on spécifie keep_empty = FALSE pour unnest()). On ré-agrége ensuite par individu avec pivot_wider(), comme précédemment :
# Je transforme les valeurs manquantes en un champs vide
data_NA$multichoice_forms[is.na(data_NA$multichoice_forms)] <- ""
# Je crée un identifiant unique
data_NA <- data_NA %>%
mutate(ID = 1:n())
data_NA$multichoice_forms <- data_NA[,nb_col_to_split]
# Je transforme la variable du choix multiple en une multitude de colonnes
data_NA_wider <- data_NA %>%
mutate(multichoice_forms = strsplit(multichoice_forms,
split = separator)) %>%
unnest(cols = multichoice_forms,
keep_empty = FALSE) %>% # je multiplie les lignes selon le nombre de réponses au choix multiple par individu (les mêmes individus sont donc dupliqués => voir de visu en arrêtant l'opération ici)
mutate(Value = 1) %>% # Je crée une valeur qui indique qu'il y a une réponse à la ligne
pivot_wider(names_from = multichoice_forms,
values_from = Value,
values_fill = 0) # J'aggrège avec pivot_wider() en remplissant d'un 0 lorsqu'il y a une valeur manquante
L’objet data_NA_wider créé contient moins de lignes que la base de données originale data_NA, puisque les lignes avec des valeurs manquantes sur la variable à désagréger n’ont pas été retenues. Pour retrouver une base de données complète, il est alors possible de fusionner ce résultat avec la base de données originale. On ne sélectionne que les nouvelles colonnes créées ainsi que l’identifiant unique, et on le fusionne avec la base de données originale. On supprime les variables temporaires, ne nous servant plus à rien, et on obtient alors le résultat voulu, avec des "NA" pour chacune des nouvelles colonnes concernant les lignes qui étaient vides :
data_NA_wider <- data_NA_wider %>%
select(ID, ncol(data_NA):ncol(data_NA_wider))
data_NA <- data_NA %>%
left_join(data_NA_wider, by = "ID") %>%
select(-multichoice_forms, -ID)
Pour vérifier que l’opération s’est bien déroulée, on sélectionne comme précédemment la variable originale qui a été désagrégée et les nouvelles colonnes issues de la désagrégation, et on les exportes dans un CSV :