Valider les données épidémiologiques

Dernière mise à jour le 2025-09-15 | Modifier cette page

Durée estimée : 12 minutes

Vue d'ensemble

Questions

  • Comment convertir les données brutes en un objet de la classe linelist ?

Objectifs

  • Démontrez comment convertir les données portant sur les cas épidémiques en objet de type linelist
  • Démontrer comment étiqueter et valider les données pour rendre l’analyse plus fiable

Pré-requis

Pour cet épisode vous devez :

  • Télécharger le fichier cleaned_data.csv
  • Et le sauvegarder dans le dossier data/.

Introduction


Après la lecture et le nettoyage des données, il est essentiel d’ajouter une étape supplémentaire fondamentale pour garantir l’intégrité et la fiabilité durant le processus d’analyse des données épidémiologiques. Dans le cas contraire, vous risquez de rencontrer des problèmes lors de l’analyse des données à cause de la création ou suppression de certaines variables ou de la modification de leur type (tel que <date> ou <chr>), etc. Plus précisément, cette étape supplémentaire implique :

  1. La vérification de la présence de certaines colonnes et de leur type de données. Ce processus est communément appelé étiquetage ;
  2. La mise en œuvre de mesures pour s’assurer que ces colonnes étiquettées ne soient pas supprimées par inadvertance lors du traitement des données. On parle de validation des données.

Cet épisode est consacré à l’étiquettage et la validation des données épidémiologiques à l’aide de la librairie {linelist}. Nous aurons besoin de la librairie rio pour importer les données, de linelist pour créer un objet de la classe linelist. Nous utiliserons l’opérateur pipe (%>%) pour connecter certaines de leurs fonctions, y compris celles de la librairie dplyr. Pour cette raison, nous allons donc charger la librairie {tidyverse}.

R

# charger packages
library(tidyverse)
library(rio)
library(here)
library(linelist) # pour etiquetter et valider les donnees

L’opérateur double deux-points (::)

L’opérateur :: de R permet d’accéder aux fonctions ou aux objets d’un package spécifique sans attacher l’intégralité du package (sans faire appel à la functionlibray()). Il offre plusieurs avantages, notamment :

  • Indiquer explicitement le package d’origine d’une fonction, réduisant ainsi les ambiguïtés et les conflits potentiels lorsque plusieurs packages possèdent des fonctions portant le même nom.
  • Permettre d’appeler une fonction depuis un package sans charger l’intégralité du package avec library().

Par exemple, la commande dplyr::filter(data, condition) signifie que nous appelons la fonction filter() depuis la librairie dplyr.

Importez le jeu de données en suivant les directives énoncées dans l’épisode document Lecture des données épidémiologiques. Il s’agit d’importer les données dans l’environnement de travail et de visualiser sa structure et son contenu.

R

# lecture des données
# supposons que le chemin d'acces au fichier
# est: data/simulated_ebola_2.csv, alors:
cleaned_data <- rio::import(
  here::here("data", "cleaned_data.csv")
) %>%
  dplyr::as_tibble()

# voir un aperçu des 10 premieres ligne du tableau de donnees
cleaned_data

SORTIE

# A tibble: 15,000 × 10
     v_1 case_id   age gender status    date_onset date_sample row_id
   <int>   <int> <dbl> <chr>  <chr>     <IDate>    <IDate>      <int>
 1     1   14905    90 male   confirmed 2015-03-15 2015-04-06       1
 2     2   13043    25 female <NA>      2013-09-11 2014-01-03       2
 3     3   14364    54 female <NA>      2014-02-09 2015-03-03       3
 4     4   14675    90 <NA>   <NA>      2014-10-19 2014-12-31       4
 5     5   12648    74 female <NA>      2014-06-08 2016-10-10       5
 6     6   14274    76 female <NA>      2015-04-05 2016-01-23       7
 7     7   14132    16 male   confirmed NA         2015-10-05       8
 8     8   14715    44 female confirmed NA         2016-04-24       9
 9     9   13435    26 male   <NA>      2014-07-09 2014-09-20      10
10    10   14816    30 female <NA>      2015-06-29 2015-02-06      11
# ℹ 14,990 more rows
# ℹ 2 more variables: years_since_collection <int>, remainder_months <int>

Discussion

Avez-vous déjà été confronté à une modification inattendue de certaines observations et/ou colonnes de vos données d’entrée lors d’une analyse épidémiologique ? Comment protégez-vous votre analyse de ce désagrément ?

Un changement inattendu

Vous êtes dans une situation d’urgence. Vous devez produire des rapports de situation quotidiennes. Vous avez automatisé votre analyse pour lire les données directement à partir du serveur en ligne :grin :. Cependant, les personnes chargées de la collecte et de l’administration des données devaient supprimer/renommer/reformater une variable qui s’est afférée utile 😞 !

Comment pouvez-vous détecter si les données saisies sont toujours valides pour reproduire l’analyse en utilisant le même code que la veille ?

Si les apprenants n’ont pas d’expérience à partager à ce sujet, nous, en tant qu’instructeurs, pouvons en partager une.

Un tel scénario se produit généralement lorsque l’institution qui effectue l’analyse des données n’est pas la même que celle qui collecte les données. Cette dernière peut prendre des décisions sur la structure et le format des données qui peuvent affecter les processus en aval et avoir un impact sur la durée l’analyse et la précision des résultats.

Création d’un objet de type linelist et étiquetage des colonnes


Après avoir importé et nettoyé les données, nous pouvons les convertir en un objet de la classe linelist à l’aide de la fonction make_linelist() de la librairie linelist comme dans l’exemple suivant ci-dessous.

R

# creer un objet de type linelist a partir des donnees nettoyees
linelist_data <- linelist::make_linelist(
  x = cleaned_data,         # les donnees d'entree
  id = "case_id",   # colonne avec les identifiants uniques des individus
  date_onset = "date_onset", # colonne avec la date d'apparition des symptomes
  gender = "gender"          # colonne ayant le genre des individus
)

# voir un aperçu de l'objet cree
linelist_data

SORTIE


// linelist object
# A tibble: 15,000 × 10
     v_1 case_id   age gender status    date_onset date_sample row_id
   <int>   <int> <dbl> <chr>  <chr>     <IDate>    <IDate>      <int>
 1     1   14905    90 male   confirmed 2015-03-15 2015-04-06       1
 2     2   13043    25 female <NA>      2013-09-11 2014-01-03       2
 3     3   14364    54 female <NA>      2014-02-09 2015-03-03       3
 4     4   14675    90 <NA>   <NA>      2014-10-19 2014-12-31       4
 5     5   12648    74 female <NA>      2014-06-08 2016-10-10       5
 6     6   14274    76 female <NA>      2015-04-05 2016-01-23       7
 7     7   14132    16 male   confirmed NA         2015-10-05       8
 8     8   14715    44 female confirmed NA         2016-04-24       9
 9     9   13435    26 male   <NA>      2014-07-09 2014-09-20      10
10    10   14816    30 female <NA>      2015-06-29 2015-02-06      11
# ℹ 14,990 more rows
# ℹ 2 more variables: years_since_collection <int>, remainder_months <int>

// tags: id:case_id, date_onset:date_onset, gender:gender 

La librairie linelist fournit des étiquettes aux variables épidémiologiques courantes et leurs associe un ensemble de types de données appropriés. Vous pouvez consulter la liste des étiquettes disponibles à partir du nom de la variable et les types de données acceptables pour chacune d’entre elles en utilisant la fonction linelist::tags_types().

Défi

Etiquettons d’autres variables. Dans certains jeu de données, il est possible de trouver des noms de variables qui sont différents des noms des étiquettes disponibles. Dans ces cas là, nous pouvons les associer en fonction de la façon dont les variables ont été définies durant la collecte des données.

Maintenant:

  • Explorer les noms de étiquettes disponibles dans {linelist}.
  • Trouver quelles autres variables de ce jeu de données peuvent être associées à l’une des étiquettes disponibles.
  • Étiquetter ces variables comme on l’a montré ci-dessus en utilisant la fonction linelist::make_linelist().

Vous pouvez accéder à la liste des noms des étiquettes disponibles dans la librairie {linelist} en utilisant :

R

# obtenir la liste des noms et types des etiquettes
linelist::tags_types()

# obtenir la liste des noms des etiquettes uniquement
linelist::tags_names()

R

linelist::make_linelist(
  x = cleaned_data,
  id = "case_id",
  date_onset = "date_onset",
  gender = "gender",
  age = "age", # meme nom que celui utilise dans la liste des etiquettes
  date_reporting = "date_sample" # noms differents mais lies
)

Comment apparaissent ces étiquettes supplémentaires dans le nouveau objet ?

Validation


Pour s’assurer que toutes les variables étiquettées sont aux normes et que leurs types de données sont correctes, utilisez la fonction linelist::validate_linelist() comme le montre l’exemple ci-dessous :

R

linelist::validate_linelist(linelist_data)

SORTIE

'linelist_data' is a valid linelist object

Défi

Imaginons le scénario suivant lors d’une épidémie en cours. Vous remarquez à un moment donné que la source de données sur laquelle vous vous appuyiez comporte un ensemble de nouvelles entrées (c’est-à-dire des lignes ou des observations) et que le type de données d’une variable a changé.

Prenons l’exemple où le type de la variable age est passé de double (<dbl>) à caractère (<chr>).

Pour simuler cette situation :

  • Modifiez le type de données de la variable,
  • Étiquetez la variable dans un object linelist, puis
  • Validez la variable.

Décrivez comment linelist::validate_linelist() réagit lorsque le type de données d’une variable a été modifié.

Nous pouvons utiliser dplyr::mutate() pour modifier le type de la variable avant de l’étiqueter pour la validation.

R

cleaned_data %>%
  # modifier le type de donnees d'une variable
  dplyr::mutate(age = as.character(age)) %>%
  # etiqueter variable
  linelist::... %>%
  # valider l'objet linelist
  linelist::...

Veuillez exécuter le code ligne par ligne, en vous concentrant uniquement sur les parties situées avant l’opérateur pipe (%>%). Après chaque étape, observez la sortie avant de passer à la ligne suivante.

Si le résultat age passe de double (<dbl>) en caractère (<chr>), nous obtenons ce qui suit :

R

cleaned_data %>%
  # convertir la variable 'age' en chaine de caracteres
  dplyr::mutate(age = as.character(age)) %>%
  # etiqueter la variable age
  linelist::make_linelist(age = "age") %>%
  # valider l'objet linelist
  linelist::validate_linelist()

ERREUR

Error: Some tags have the wrong class:
  - age: Must inherit from class 'numeric'/'integer', but has class 'character'

Pourquoi recevons-nous un message d'Erreur ?

Devrions-nous avoir un message d’alerte à la place ? Expliquez pourquoi. Explorez d’autres situations pour comprendre ce comportement en convertissant:

  • date_onset de <date> en caractère (<chr>),
  • gender de caractère (<chr>) en nombre entier (<int>).

Ensuite, étiquetez-les dans dans l’objet linelist pour validation. Est-ce que le message d'Erreur nous propose-t-il une solution ?

R

# deuxieme changement
# executer ce code ligne par ligne pour voir les changements
cleaned_data %>%
  # modifier le type de la variable 'date_onset'
  dplyr::mutate(date_onset = as.character(date_onset)) %>%
  # tiqueter le variable 'date_onset'
  linelist::make_linelist(
    date_onset = "date_onset"
  ) %>%
  # valider l'objet linelist
  linelist::validate_linelist()

R

# troisieme changement
# executer ce code ligne par ligne pour voir les changements
cleaned_data %>%
  # modifier le type de la variable 'gender'
  dplyr::mutate(gender = as.factor(gender)) %>%
  dplyr::mutate(gender = as.integer(gender)) %>%
  # etiqueter la variable 'gender'
  linelist::make_linelist(
    gender = "gender"
  ) %>%
  # valider l'objet linelist
  linelist::validate_linelist()

Nous obtenons des messages d'Erreur car le type par défaut de ces variables dans linelist::tags_types() est différent de celui dont on les a associé.

Le message d'Erreur nous informe que pour valider notre objet linelist, nous devons changer le type de variable d’entrée de sorte qu’il corresponde au type d’étiquette attendu. Dans un script d’analyse de données, nous pouvons le faire en ajoutant une étape de nettoyage dans le pipeline.

Défi

En dehors de l’étiquetage et de la validation de l’objet linelist, de quelle autre étape avons-nous besoin lors de la construction de l’objet ?

Voici un scénario où nous allons essayer d’étiqueter une variable qui n’existe pas dans notre jeu de données.

R

cleaned_data %>%
  # supprimer la variable 'age'
  select(-age) %>%
  # etiqueter la variable 'age' qui n'existe plus
  linelist::make_linelist(age = "age")

ERREUR

Error in base::tryCatch(base::withCallingHandlers({: 1 assertions failed:
 * Variable 'tag': Must be element of set
 * {'v_1','case_id','gender','status','date_onset','date_sample','row_id','years_since_collection','remainder_months'},
 * but is 'age'.

On a donc besoin de mettre en place un mécanisme pour protéger les données de toutes actions inopportunes.

Protéger les données


La protection des données est implicitement intégrée dans les objets de la classe linelist. Si vous essayez de supprimer l’une des variables étiquetées, vous recevrez un message d’erreur ou d’avertissement, comme le montre l’exemple ci-dessous.

R

new_df <- linelist_data %>%
  dplyr::select(case_id, gender)

AVERTISSEMENT

Warning: The following tags have lost their variable:
 date_onset:date_onset

Ce message d’avertissement qui s’affiche est l’option par défaut lorsque nous perdons des étiquetes dans un objet de la classe linelist. Cependant, il peut être remplacé par un message d'Erreur en utilisant la fonction linelist::lost_tags_action().

Défi

Testons les implications de la variation de la configuration de protection d’un objet linelist de Avertissement à Erreur.

  • Tout d’abord, exécutez ce code pour compter la fréquence des catégorie au sein d’une variable catégorielle :

R

linelist_data %>%
  dplyr::select(case_id, gender) %>%
  dplyr::count(gender)
  • Spéficier qu’on souhaite obtenir un message d’Erreur au lieu d’un Avertissement à la suite de la perte d’une variable étiquetée de l’objet linelist :

R

# retourner une erreur
linelist::lost_tags_action(action = "error")
  • Maintenant, réexécutez le bloc de code ci-dessus avec dplyr::count().
  • Quelle est la différence entre le message d'Avertissement et le message d'Erreur ?
  • Quelles pourraient être les implications de ce changement pour votre pipeline d’analyse quotidienne de données lors d’une réponse à une épidémie ?

Décider entre Avertir et continuer l'exécution du code ou Arréter l'exécution du code avec un message d'erreur dépendra du niveau d’importance et de flexibilité dont vous avez besoin lorsque vous perdez des étiquettes. L’un vous alertera d’un changement mais continuera à exécuter le code en aval. L’autre arrêtera votre pipeline d’analyse et le reste ne sera pas exécuté.

Un script de lecture, nettoyage et validation de données peut nécessiter un pipeline plus stable ou fixe. Une analyse exploratoire des données peut nécessiter une approche plus souple. Ces deux processus peuvent être isolés dans des scripts ou des dossiers différents afin d’adapter le mécanisme de protection à vos besoins.

Avant de continuer, rétablissez la configuration à l’option par défaut de Avertissement:

R

# retablir l'option par defaut: "warning"
linelist::lost_tags_action()

SORTIE

Lost tags will now issue a warning.

A objet linelist ressemble à un data frame mais offre des caractéristiques et fonctionnalités plus riches. Les librairies qui prennent en compte les objets linelist peuvent exploiter ces fonctionnalités. Par exemple, vous pouvez extraire un data frame contenant uniquement les colonnes étiquetées à l’aide de la fonction linelist::tags_df() comme indiqué ci-dessous :

R

# extraire uniquement les colonnes étiquetées
linelist::tags_df(linelist_data)

SORTIE

# A tibble: 15,000 × 3
      id date_onset gender
   <int> <IDate>    <chr>
 1 14905 2015-03-15 male
 2 13043 2013-09-11 female
 3 14364 2014-02-09 female
 4 14675 2014-10-19 <NA>
 5 12648 2014-06-08 female
 6 14274 2015-04-05 female
 7 14132 NA         male
 8 14715 NA         female
 9 13435 2014-07-09 male
10 14816 2015-06-29 female
# ℹ 14,990 more rows

Avec la librairie cleanepi, vous pouvez également choisir d’appliquer certaines opérations de nettoyage de données uniquement sur les les colonnes étiquetées. Il suffira de donner la valeur "linelist_tags" à l’argument target_columns de la finction correspondante.

R

# identifier les doublons uniquement à travers les colonnes etiquetees
linelist_data %>%
  cleanepi::find_duplicates(target_columns = "linelist_tags")

SORTIE

! Found 177 duplicated rows in the dataset.
ℹ Use `attr(dat, "report")[["duplicated_rows"]]` to access them, where "dat" is
  the object used to store the output from this operation.

SORTIE


// linelist object
# A tibble: 15,000 × 10
     v_1 case_id   age gender status    date_onset date_sample row_id
   <int>   <int> <dbl> <chr>  <chr>     <IDate>    <IDate>      <int>
 1     1   14905    90 male   confirmed 2015-03-15 2015-04-06       1
 2     2   13043    25 female <NA>      2013-09-11 2014-01-03       2
 3     3   14364    54 female <NA>      2014-02-09 2015-03-03       3
 4     4   14675    90 <NA>   <NA>      2014-10-19 2014-12-31       4
 5     5   12648    74 female <NA>      2014-06-08 2016-10-10       5
 6     6   14274    76 female <NA>      2015-04-05 2016-01-23       7
 7     7   14132    16 male   confirmed NA         2015-10-05       8
 8     8   14715    44 female confirmed NA         2016-04-24       9
 9     9   13435    26 male   <NA>      2014-07-09 2014-09-20      10
10    10   14816    30 female <NA>      2015-06-29 2015-02-06      11
# ℹ 14,990 more rows
# ℹ 2 more variables: years_since_collection <int>, remainder_months <int>

// tags: id:case_id, date_onset:date_onset, gender:gender 

Quand dois-je utiliser {linelist}?

L’analyse des données au cours d’une réponse à une épidémie ou d’une surveillance de masse exige un ensemble de différentes façons de “protéger les données” par rapport aux situations de recherche habituelles. Par exemple, vos données changeront ou seront mises à jour au fil du temps avec de nouvelles entrées, nouvelles variables, des variables seront renommées, etc.

La librairie linelist est plus appropriée pour ce type de surveillance continue, mais aussi aux analyses de données générée sur une longue période. Consultez la section de la vignette “Get started” à propos de When I should consider using {linelist}? pour plus d’informations.

Points clés

  • Utiliser la librairie linelist pour étiqueter, valider et protéger les données épidémiologiques pour l’analyse en aval.