Skip to contents

Pourquoi ?

Cette vignette a pour but d’expliciter l’usage d’impactR et la manière dont il est possible de l’utiliser dans le cadre d’un suivi de collecte de données et du nettoyage. Commençons par charger le package.

# Si vous n'avez pas encore installé le package
# devtools::install_github("impactR)
library(impactR)

Ci-dessus, on peut charger des données exemple collectées.

# Load dataset in environment
data(data)

# Show the first lines and types of airports' tibble
data <- data |> tibble::as_tibble()
data
## Warning in as.POSIXlt.POSIXct(x, tz): unable to identify current timezone 'H':
## please set environment variable 'TZ'
## # A tibble: 30 × 52
##    uuid  cluster   weights start               end                
##    <chr> <chr>       <dbl> <dttm>              <dttm>             
##  1 x1    wendou_1      0.8 2021-10-18 09:08:24 2021-10-18 10:01:35
##  2 x2    wendou_1      0.8 2021-10-20 09:14:47 2021-10-20 10:05:23
##  3 x3    wendou_2      0.8 2021-10-20 10:11:14 2021-10-20 11:00:07
##  4 x4    wendou_2      0.8 2021-10-18 09:08:24 2021-10-20 12:02:57
##  5 x5    wendou_1      0.8 2021-10-20 10:11:14 2021-10-20 15:02:31
##  6 x6    wendou_2      0.8 2021-10-20 14:14:36 2021-10-20 16:04:35
##  7 x7    wendou_1      0.8 2021-10-20 15:09:11 2021-10-20 10:26:34
##  8 x8    wendou_1      0.8 2021-10-20 09:44:15 2021-10-20 11:12:48
##  9 x9    gnarala_1     1.2 2021-10-20 11:12:05 2021-10-21 11:12:48
## 10 x10   gnarala_2     1.2 2021-10-20 14:14:36 2021-10-22 11:12:48
## # … with 20 more rows, and 47 more variables: today <dttm>, deviceid <chr>,
## #   i_enum_id <dbl>, i_enum_genre <chr>, i_admin2 <chr>, i_ville <chr>,
## #   i_secteur <chr>, i_info_secteur <chr>, i_zad <chr>, i_zad_1 <chr>,
## #   i_consensus <chr>, i_consensus_note <chr>, i_enquete_age <dbl>,
## #   i_enquete_genre <chr>, i_statut <chr>, i_note_statut <lgl>,
## #   i_statut_1 <chr>, c_note <lgl>, c_chef_menage <chr>,
## #   c_n_chef_menage_genre <chr>, c_n_chef_menage_age <dbl>, …

La plupart des fonctions de impactR sont écrites en supposant que les données fournies peuvent être converties en tibble, puisqu’elles utilisent largement le tidyverse.

Supposons que nous ayons une feuille ‘survey’ composée comme suit :

data(survey)
survey <- survey |> tibble::as_tibble(survey)

survey
## # A tibble: 44 × 12
##    type        name  label hint  requi…¹ choic…² calcu…³ relev…⁴ const…⁵ const…⁶
##    <chr>       <chr> <chr> <lgl> <lgl>   <chr>   <chr>   <chr>   <chr>   <chr>  
##  1 start       start NA    NA    NA      NA      NA      NA      NA      NA     
##  2 end         end   NA    NA    NA      NA      NA      NA      NA      NA     
##  3 today       today NA    NA    NA      NA      NA      NA      NA      NA     
##  4 deviceid    devi… NA    NA    NA      NA      NA      NA      NA      NA     
##  5 select_one… i_en… Code… NA    TRUE    NA      NA      NA      NA      NA     
##  6 select_one… i_en… Sexe… NA    TRUE    NA      NA      NA      NA      NA     
##  7 hidden      i_ad… Quel… NA    FALSE   NA      NA      NA      NA      NA     
##  8 hidden      i_vi… Quel… NA    FALSE   NA      NA      NA      NA      NA     
##  9 select_one… i_se… Quel… NA    TRUE    NA      NA      NA      NA      NA     
## 10 calculate   i_in… NA    NA    TRUE    NA      jr:cho… NA      NA      NA     
## # … with 34 more rows, 2 more variables: given_name <lgl>, default <chr>, and
## #   abbreviated variable names ¹​required, ²​choice_filter, ³​calculation,
## #   ⁴​relevant, ⁵​constraint, ⁶​constraint_message

La première chose à faire avec l’objet ‘survey’, car il sera utilisé ailleurs : il faut séparer en deux la colonne ‘type’.

# Miseà part l'argument 'col_to_split' (la colonne à séparer), les autres paramètres sont les paramètres par défaut
survey <- survey |>  
  split_survey(
    col_to_split = "type",
    into = c("type", "list_name"),
    sep = " ",
    fill = "right")

survey
## # A tibble: 44 × 13
##    type       list_n…¹ name  label hint  requi…² choic…³ calcu…⁴ relev…⁵ const…⁶
##    <chr>      <chr>    <chr> <chr> <lgl> <lgl>   <chr>   <chr>   <chr>   <chr>  
##  1 start      NA       start NA    NA    NA      NA      NA      NA      NA     
##  2 end        NA       end   NA    NA    NA      NA      NA      NA      NA     
##  3 today      NA       today NA    NA    NA      NA      NA      NA      NA     
##  4 deviceid   NA       devi… NA    NA    NA      NA      NA      NA      NA     
##  5 select_one l_enum_… i_en… Code… NA    TRUE    NA      NA      NA      NA     
##  6 select_one l_genre  i_en… Sexe… NA    TRUE    NA      NA      NA      NA     
##  7 hidden     NA       i_ad… Quel… NA    FALSE   NA      NA      NA      NA     
##  8 hidden     NA       i_vi… Quel… NA    FALSE   NA      NA      NA      NA     
##  9 select_one l_secte… i_se… Quel… NA    TRUE    NA      NA      NA      NA     
## 10 calculate  NA       i_in… NA    NA    TRUE    NA      jr:cho… NA      NA     
## # … with 34 more rows, 3 more variables: constraint_message <chr>,
## #   given_name <lgl>, default <chr>, and abbreviated variable names ¹​list_name,
## #   ²​required, ³​choice_filter, ⁴​calculation, ⁵​relevant, ⁶​constraint

Contrôle de la qualité des données

Journal de nettoyage des valeurs aberrantes

Afin de pouvoir obtenir les valeurs dites aberrantes (pour les variables numériques), vous pouvez utiliser la fonction make_log_outlier qui permet d’obtenir deux types de valeurs aberrantes : l’écart par rapport à la moyenne en utilisant la fonction outliers_sd et l’écart interquartile en utilisant la fonction outliers_iqr.

# Utilitaire pour obtenir toutes les variables numériques
#numeric_cols(data) #  Obtenir toutes les colonnes numériques : cela inclut par exemple les identifiants numériques des énumérateurs ou les points GPS.
#numeric_cols(data, survey) # Obtenir toutes les colonnes numériques en utilisant la feuille 'survey' de l'outil Kobo (uniquement les calculate, integer, etc.)

# Valeurs aberrantes interquartle (règle des 1,5 fois par défaut)
#outliers_iqr(data, col = i_enquete_age,times = 1.5,  id_col = uuid) # La colonne d'identifiant 'id_col' est habituellement "uuid" avec Kobo

# Valeurs aberrantes à la moyenne
#outliers_sd(data, i_enquete_age, times = 3, id_col = uuid)

# Fabriquer le journal de nettoyage entier pour toutes les variables numériques (en prenant en compte l'outil Kobo)
log_outliers <- make_log_outlier(data, survey, id_col = uuid, today, i_enum_id, i_zad)
log_outliers
## # A tibble: 2 × 16
##   id_check today               i_enu…¹ i_zad uuid  quest…² quest…³ why   feedb…⁴
##   <chr>    <dttm>                <dbl> <chr> <chr> <chr>   <chr>   <chr> <chr>  
## 1 outlier  2021-10-18 00:00:00       8 wend… x1    c_n_ch… Quel e… Outl… Fill in
## 2 outlier  2021-10-20 00:00:00       3 wend… x2    c_n_ch… Quel e… Outl… Fill in
## # … with 7 more variables: action <chr>, old_value <dbl>, new_value <chr>,
## #   type <chr>, other_parent_question <chr>, other_new_value <chr>,
## #   checkdate <chr>, and abbreviated variable names ¹​i_enum_id, ²​question_name,
## #   ³​question_label, ⁴​feedback

Journal de nettoyage des “autres”

Cette fonction nécessite que la question Kobo avec la réponse “autre” soit définie comme “variable” pour la question parent et “autre_variable” pour la question parent. “autre_” peut être différent selon les outils et est défini dans la question suivante par l’argument “autre”, qui est la chaîne de caractères de chaque début de variable autre codée dans Kobo. Dans l’exemple qui suit, il s’agit de “autre_”.

# Obtenir les autres 
other_cols <- other_cols(data, "autre_", id_col = uuid)
other_cols
## # A tibble: 4 × 4
##   uuid  question_name             old_value                 other_parent_quest…¹
##   <chr> <chr>                     <chr>                     <chr>               
## 1 x5    autre_h_3_type_latrine    Aussi latrines communales h_3_type_latrine    
## 2 x7    autre_r_besoin_assistance Un métier                 r_besoin_assistance 
## 3 x15   autre_r_besoin_assistance Electricité               r_besoin_assistance 
## 4 x22   autre_h_3_type_latrine    Trou ouvert               h_3_type_latrine    
## # … with abbreviated variable name ¹​other_parent_question
# Obtenir les autres parents
other_parent_cols(data, other_cols, "autre_", id_col = uuid)
## # A tibble: 4 × 3
##   uuid  other_parent_question other_old_value            
##   <chr> <chr>                 <chr>                      
## 1 x15   r_besoin_assistance   abri_bna secal autre       
## 2 x22   h_3_type_latrine      latrine_prive autre        
## 3 x5    h_3_type_latrine      latrine_prive_partage autre
## 4 x7    r_besoin_assistance   abri_bna secal autre
# Fabriquer le journal de nettoyage des "autres"
log_others <- make_log_other(data, survey, "autre_", uuid, today, i_enum_id, i_zad) 
log_others
## # A tibble: 4 × 17
##   id_check today               i_enu…¹ i_zad uuid  quest…² quest…³ why   feedb…⁴
##   <chr>    <dttm>                <dbl> <chr> <chr> <chr>   <chr>   <chr> <chr>  
## 1 autre_   2021-10-20 00:00:00       3 wend… x5    autre_… Lesque… Othe… Fill in
## 2 autre_   2021-10-20 00:00:00      12 wend… x7    autre_… De que… Othe… Fill in
## 3 autre_   2021-10-20 00:00:00       3 gnar… x15   autre_… De que… Othe… Fill in
## 4 autre_   2021-10-20 00:00:00       5 gnar… x22   autre_… Lesque… Othe… Fill in
## # … with 8 more variables: action <chr>, old_value <chr>, new_value <chr>,
## #   type <chr>, other_parent_question <chr>, other_old_value <chr>,
## #   other_new_value <chr>, checkdate <chr>, and abbreviated variable names
## #   ¹​i_enum_id, ²​question_name, ³​question_label, ⁴​feedback

Journal de nettoyage basé sur une liste de vérifications

Il suffit d’avoir produit en amont un fichier Excel de vérification logique, qu’il est par ailleurs possible de modifier au cours de la collecte.

data(check_list)
check_list <- check_list |> tibble::as_tibble()
check_list
## # A tibble: 5 × 7
##   id_check question_name     why                    logic…¹ new_v…² action type 
##   <chr>    <chr>             <chr>                  <chr>   <lgl>   <chr>  <chr>
## 1 id1      i_consensus       Pas de consentement p… "i_con… NA      remove char…
## 2 id2      survey_duration   Durée d'enquête de mo… "surve… NA      urgen… doub…
## 3 id3      survey_duration   Durée d'enquête de pl… "surve… NA      check  doub…
## 4 id4      survey_duration   Durée d'enquête de pl… "surve… NA      urgen… doub…
## 5 id5      c_chef_menage_age Le ou la cheffe de mé… "c_che… NA      check  doub…
## # … with abbreviated variable names ¹​logical_test, ²​new_value

Le tableur excel de vérifications doit suivre quelques règles pour pouvoir être lu par les fonctions d’impactR [ajouter la liste]. Par exemple, il est nécessaire que toutes les variables présentes dans les tests logiques (colonne ‘logical_test’ du tableau de vérifications) existent aussi dans les données, objet data. Pour cela, on peut utiliser la fonction check_check_list, qui vise à valider ou non un tableur de vérifications logiques [note : elle n’est pas encore robuste, mais elle permet déjà de faire un certain nombre de contrôles].

Par exemple, ci-dessous la colonne survey_duration n’existe pas dans les données data. Pourtant, il y a des vérifications logiques qui la prennent en compte dans le tableur de vérifications logiques check_list. Si on lance la commande suivante, on obtiendrait une erreur :

check_check_list(check_list, data)
# following column/s from `question_name` is/are missing in `.tbl`: survey_duration, survey_duration, survey_duration

On va donc jouter la colonne de durée d’enquête à l’aide de la fonction survey_duration. On en profite pour assi ajouter la différence de temps entre deux enquêtes par enquêteur.rice :

data <- data |> 
  survey_duration(start, end, new_colname = "survey_duration") #|>
  # NOT RUN!
  # survey_difftime(start, end, new_colname = "survey_difftime", i_enum_id)
data$survey_duration
##  [1]   53   51   49 3055  291  110 -283   89 1441 2698 1204 2969 1481 5884 1558
## [16] 2942 4444 2942 1258 2644 1529 2881 1258 2644 1529 2921 1529 5884 1502 2698

On peut vérifier de nouveau le tableur de vérifications logiques :

check_check_list(check_list, data)
## [1] TRUE

Cette fois-ci, c’est bon, la fonction donne TRUE, on peut donc procéder avec la production du log de nettoyage.

log_check_list <- make_log_from_check_list(data, survey, check_list, uuid, today, i_enum_id, i_zad)

log_check_list
## # A tibble: 57 × 17
##    id_ch…¹ today               i_enu…² i_zad uuid  quest…³ quest…⁴ why   feedb…⁵
##    <chr>   <dttm>                <dbl> <chr> <chr> <chr>   <chr>   <chr> <chr>  
##  1 id2     2021-10-20 00:00:00      12 wend… x7    survey… ""      Duré… Verifi…
##  2 id3     2021-10-18 00:00:00       8 wend… x1    survey… ""      Duré… Verifi…
##  3 id3     2021-10-20 00:00:00       3 wend… x2    survey… ""      Duré… Verifi…
##  4 id3     2021-10-20 00:00:00       3 wend… x3    survey… ""      Duré… Verifi…
##  5 id3     2021-10-20 00:00:00       3 wend… x4    survey… ""      Duré… Verifi…
##  6 id3     2021-10-20 00:00:00       3 wend… x5    survey… ""      Duré… Verifi…
##  7 id3     2021-10-20 00:00:00       3 wend… x6    survey… ""      Duré… Verifi…
##  8 id3     2021-10-20 00:00:00      12 wend… x8    survey… ""      Duré… Verifi…
##  9 id3     2021-10-20 00:00:00       1 gnar… x9    survey… ""      Duré… Verifi…
## 10 id3     2021-10-20 00:00:00       5 gnar… x10   survey… ""      Duré… Verifi…
## # … with 47 more rows, 8 more variables: action <chr>, old_value <chr>,
## #   new_value <lgl>, type <chr>, other_parent_question <chr>,
## #   other_old_value <chr>, other_new_value <chr>, checkdate <chr>, and
## #   abbreviated variable names ¹​id_check, ²​i_enum_id, ³​question_name,
## #   ⁴​question_label, ⁵​feedback

Journal de nettoyage complet et exportation

Pour terminer, il nous suffit de combiner tous ces journaux de nettoyage en un seul. On peut ensuite l’exporter en fichier excel.

log <- list(log_outliers, log_check_list, log_others) |> 
  purrr::map(~ .x |> dplyr::mutate(dplyr::across(.fns = as.character))) |> 
  dplyr::bind_rows() |> 
  readr::type_convert()

Il est aussi possible d’utiliser la fonction make_all_logs qui combine ces trois fonctions et ne sort qu’un unique journal de nettoyage.

log <- make_all_logs(data, survey, check_list, "autre_", uuid, today, i_enum_id, i_zad)
log
## # A tibble: 63 × 17
##    id_check today      i_enum…¹ i_zad uuid  quest…² quest…³ why   feedb…⁴ action
##    <chr>    <date>        <dbl> <chr> <chr> <chr>   <chr>   <chr> <chr>   <chr> 
##  1 id2      2021-10-20       12 wend… x7    survey… NA      Duré… Verifi… urgen…
##  2 id3      2021-10-18        8 wend… x1    survey… NA      Duré… Verifi… check 
##  3 id3      2021-10-20        3 wend… x2    survey… NA      Duré… Verifi… check 
##  4 id3      2021-10-20        3 wend… x3    survey… NA      Duré… Verifi… check 
##  5 id3      2021-10-20        3 wend… x4    survey… NA      Duré… Verifi… check 
##  6 id3      2021-10-20        3 wend… x5    survey… NA      Duré… Verifi… check 
##  7 id3      2021-10-20        3 wend… x6    survey… NA      Duré… Verifi… check 
##  8 id3      2021-10-20       12 wend… x8    survey… NA      Duré… Verifi… check 
##  9 id3      2021-10-20        1 gnar… x9    survey… NA      Duré… Verifi… check 
## 10 id3      2021-10-20        5 gnar… x10   survey… NA      Duré… Verifi… check 
## # … with 53 more rows, 7 more variables: old_value <chr>, new_value <chr>,
## #   type <chr>, other_parent_question <chr>, other_old_value <chr>,
## #   other_new_value <lgl>, checkdate <chr>, and abbreviated variable names
## #   ¹​i_enum_id, ²​question_name, ³​question_label, ⁴​feedback

Enfin, il existe plusieurs manière d’exporter. Ici on donne l’exemple avec le package writexl:

# Not run! La plus simple
# writexl::write_xlsx(log, "output/log.xlsx)

# On peut y ajouter la date du jour pour permettre le suivi
# writexl::write_xlsx(log, paste0("output/log_", Sys.Date(), ".xlsx))