Documentation
  1. Data integration [FR]
  2. Recensement des projets
  • Introduction
    • Purpose of this documentation
    • Contribute to this documentation
  • Database
    • Database structure
    • Lab results importation example
    • Database query
  • Data integration [FR]
    • Recensement des projets
    • Recensement des sites
    • Consolidation de la nomenclature des analytes
    • Description des contaminants
    • Déterminer la taille des échantillons par site
    • Injections des données

On this page

  • Établir une liste des projets
  • Convertion des documents Word en pdf
  • Extraire les métadonnées du rapport
  • Valider l’existence de rapports de laboratoire dans le dossier 01-Projet et suivis
  1. Data integration [FR]
  2. Recensement des projets

Recensement des projets

Author

Steve Vissault

Published

March 19, 2024

Établir une liste des projets

Chaque rapport de laboratoire contient sur sa page de garde l’ensemble des métadonnées en lien avec le projet de recherche pour lequel cette analyse a été demandé. On désire donc extraire la page de garde de chacun des rapports de laboratoires afin d’obtenir la liste des projets.

Un rapport de laboratoire peut être detectable dans une liste de fichier par la structure de son identifiant unique. Voici un exemple d’identifiant unique: CHEM-PCDD-00-07 ou encore MB-05-10. Ces identifiants ont une structure unique que l’on peut detecter grace à l’expression régulière suivante:

regex_report_id <- "([A-Za-z]{2,5}-)?[A-Za-z]{2,5}-\\d{2}-\\d{2}"

La variable regex_report_id sera utilisée plusieurs fois dans ce document.

On liste les rapports de laboratoire présents dans le dossier 03-Labo/Results Reports.

reports_path <- list.files(
    "C:/Users/VissaultS/Documents/03-Labo/Results Reports", 
    pattern = "*.pdf|*.docx|*.doc", recursive = TRUE, full.names = TRUE
)

# On extrait les identifiants des rapports du nom du fichier
report_id <- stringr::str_extract(reports_path, regex_report_id)

# On obtient la signature du fichier, ca va être pratique pour detecter les fichiers dupliqués même si le nom du fichier est différent.
file_hash <- tools::md5sum(reports_path)

# On extrait l'extension du fichier
file_ext <- reports_path |> 
    strsplit("[.]") |> 
    purrr::map_chr(\(e) return(e[2]))

# On compose un tableau avec l'ensemble de ces informations
reports <- data.frame(
        path = reports_path, 
        id = report_id, 
        hash = file_hash, 
        ext = file_ext
    ) |> tibble::as_tibble()

Note: tools::md5sum permet de générer une signature unique propre au fichier. Ainsi deux fichiers identiques dans le contenu mais avec des noms différents pourront être identifié comme des duplicats.

Voici la liste des fichiers identiques dans le dossier 03-Labo/Results Reports.

reports_dup <- reports |> 
    tibble::as_tibble() |>
    janitor::get_dupes(-c(path)) |>
    dplyr::select(-hash)

reports_dup |> knitr::kable()
id ext dupe_count path
BMK-PFC-23-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/BMK-PFC-23-10_HERG-COEI_eggs2023.pdf
BMK-PFC-23-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/EideràDuvet Rapports 1972-2023/BMK-PFC-23-10_HERG-COEI_eggs2023.pdf
BMK-PFC-23-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/BMK-PFC-23-10_HERG-COEI_eggs2023.pdf
CHEM-OC-22-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/CHEM-OC-22-10_GBHE-HERG2022.pdf
CHEM-OC-22-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/CHEM-OC-22-10_GBHE-HERG2022.pdf
CHEM-OC-22-10 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GrandHeron Rapports xxxx-2022/Rapports/CHEM-OC-22-10_GBHE-HERG2022.pdf
MET-THg-22-05 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/MET-THg-22-05 - RALA01-2022_HERG-GBHEegg2022.pdf
MET-THg-22-05 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GrandHeron Rapports xxxx-2022/Rapports/MET-THg-22-05 - RALA01-2022_HERG-GBHEegg2022.pdf
MET-THg-22-05 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/MET-THg-22-05 - RALA01-2022_HERG-GBHEegg2022.pdf
MET-THg-23-13 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/EideràDuvet Rapports 1972-2023/MET-THg-23-13 - RALA01-2023.pdf
MET-THg-23-13 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/MET-THg-23-13 - RALA01-2023.pdf
MET-THg-23-13 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/MET-THg-23-13 - RALA01-2023_OeufsCOEI-HERG2023.pdf
TP-SI-22-09 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/TP-SI-22-09C_RALA01-2022_HERG-GBHEeggs2022.pdf
TP-SI-22-09 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GrandHeron Rapports xxxx-2022/Rapports/TP-SI-22-09C_RALA01-2022_HERG-GBHEeggs2022.pdf
TP-SI-22-09 pdf 3 C:/Users/VissaultS/Documents/03-Labo/Results Reports/TP-SI-22-09C_RALA01-2022_HERG-GBHEeggs2022.pdf
CHEM-OC-21-08 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/CHEM-OC-21-08R.pdf
CHEM-OC-21-08 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/FouBassan Rapports 1984-2019/CHEM-OC-21-08R.pdf
CHEM-OC-22-05 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/CHEM-OC-22-05_HERGDeslauriers.pdf
CHEM-OC-22-05 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/GoelandArgente 2017, 2022-23/CHEM-OC-22-05_HERGDeslauriers.pdf
CHEM-OC-23-08 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/CHEM-OC-23-08_EggHERG_COEI_2023.pdf
CHEM-OC-23-08 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/EideràDuvet Rapports 1972-2023/CHEM-OC-23-08_EggHERG_COEI_2023.pdf
MET-THg-21-03 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/FouBassan Rapports 1984-2019/MET-THg-21-03.pdf
MET-THg-21-03 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/MET-THg-21-03 - RALA01-2021_eggs.pdf
TP-SI-21-05 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/FouBassan Rapports 1984-2019/TP-SI-21-05C.pdf
TP-SI-21-05 pdf 2 C:/Users/VissaultS/Documents/03-Labo/Results Reports/TP-SI-21-05C_RALA01-2021.pdf

On selectionne le premier rapport en se basant sur le id (ex. BMK-PFC-23-01) pour éliminer les rapports dupliqués pour la suite de l’analyse. On s’assure de selectionner préférablement les pdfs si on dispose d’un docx et d’un document pdf pour le même identifiant de rapport de laboratoire.

reports <- reports |> 
    # On retire les rapports qui sont dupliqués
    dplyr::group_by(hash) |>
    dplyr::slice(1) |>
    dplyr::ungroup() |>
    # Si plusieurs extension de fichiers, on selectionne ceux en PDF préférablement, sinon .docx, sinon .doc en dernier recours.
    dplyr::group_split(id) |>
    purrr::map(\(g){
        g |> dplyr::arrange(factor(ext, levels = c('pdf', 'docx', 'doc'))) |>
        dplyr::slice(1)
    }) |>
    dplyr::bind_rows()

Quelques rapports de laboratoire demeurent au format doc et docx.

docs <- reports |> dplyr::filter(ext %in% c('doc', 'docx')) 
docs |> knitr::kable()
path id hash ext

Afin de faciliter l’extraction des métadonnées par programmation, on convertit les fichiers .doc et .docx en pdf.

Convertion des documents Word en pdf

Cette étape a été complété manuellement.

Extraire les métadonnées du rapport

Nous souhaitons générer une liste de tous les projets basée sur les 71 rapports de laboratoire stockés dans le dossier 03-Labo/Comptes rendus de résultats. La première page de chaque rapport de laboratoire contient toutes les informations pertinentes pour produire cette liste.

Pour chaque rapport, nous vérifions s’il s’agit d’une image ou non. Si le rapport est une image, nous devons utiliser une reconnaissance optique de caractères (OCR) afin d’extraire le texte de la première page et d’obtenir toutes les métadonnées pertinentes. Si c’est un pdf ou un fichier word, nous importons la première page du document.

# On détect si le document est une image
reports <- reports |> dplyr::mutate(
    filename = basename(path),
    is_image = purrr::map2_lgl(path, ext, \(p, e) {
        if(e == "pdf"){
            out <- pdftools::pdf_text(p)
            !all(nchar(out) > 15)
        } else {
            FALSE
        }
    })
)

# On extrait le texte par OCR si c'est une image
frontpages <- purrr::map2_vec(reports$path, reports$is_image, \(p, i) {
        ifelse(isTRUE(i), 
            pdftools::pdf_ocr_text(pdf = p, pages = 1),
            pdftools::pdf_text(pdf = p)[[1]]
        )
    }) |> tolower()

Une fois le texte de la première page isolé, on applique une série d’opération d’extractions de texte à partir de la position de mots clés. On isole ainsi le titre du projet, l’ID du projet, la date etc.

project_id <- purrr::map_vec(frontpages, \(f){
    stringr::str_extract(f, "(?<=(project: |project |projects|projet :)).*(?=\n)")
}) |> 
    toupper() |> 
    stringr::word(1) |> 
    stringr::str_replace_all("[.,]", "") |>
    stringr::str_trim() |>
    dplyr::na_if("")

project_leader <- purrr::map_vec(frontpages, \(f){
        stringr::str_extract(f, "(?<=(project leader: |project leader |project manager: |manager: |study leader: |nom du requérant :)).*(?=\n)")
    }) |> 
    stringr::str_replace_all(c("[_|:]" = "", "[:digit:]" = "", "[.]$" = "")) |> 
    stringr::str_to_title() |>
    stringr::str_trim()

project_dates <- frontpages |>
    purrr::map_vec(\(f){
        dates <- stringr::str_extract(f, "\\d{4}-\\d{2}-\\d{2}")
        if(is.na(dates)) {
            dates <- stringr::str_extract(f, "(?<=(date: )).*(?=\n)")
        }
        return(dates)
    }) 
        
reportsProject <- data.frame(
    report_id = reports$id, 
    report_access_path = stringr::str_replace_all(reports$path, "C:/Users/VissaultS/Documents", "Z:"), 
    project_id, project_leader, project_dates, project_title = NA
)

Le data.frame reportsProject est à la base du fichier “Z:\07-Données BD_projects_list_extract_25032024.xlsx”.

Valider l’existence de rapports de laboratoire dans le dossier 01-Projet et suivis

On valide si certains de ces rapports ne se retrouvent pas dans le dossier 03-Labo/Comptes rendus. Ces rapports pourraient potentiellement nous interressés.

files <- list.files(
    "C:/Users/VissaultS/Documents/01-Projets et suivis", 
    pattern = "*.pdf|*.docx|*.doc", recursive = TRUE, full.names = TRUE
)

potential_reports <- data.frame(file = files[which(stringr::str_detect(files, regex_report_id))])

potential_reports <- potential_reports |> dplyr::mutate(
    id = stringr::str_extract(file, regex_report_id) |> toupper(),
    in_lab_report_folder = !(id %in% reports$id)
) |> dplyr::arrange(in_lab_report_folder) |>
    dplyr::mutate(file = stringr::str_replace(file, "C:/Users/VissaultS/Documents/", "Z:"))
Source Code
---
title: "Recensement des projets"
author: "Steve Vissault"
date: "2024-03-19"
---

## Établir une liste des projets

Chaque rapport de laboratoire contient sur sa page de garde l'ensemble des métadonnées en lien avec le projet de recherche pour lequel cette analyse a été demandé. On désire donc extraire la page de garde de chacun des rapports de laboratoires afin d'obtenir la liste des projets.

Un rapport de laboratoire peut être detectable dans une liste de fichier par la structure de son identifiant unique. Voici un exemple d'identifiant unique: `CHEM-PCDD-00-07` ou encore `MB-05-10`. Ces identifiants ont une structure unique que l'on peut detecter grace à l'expression régulière suivante:

```{r}
regex_report_id <- "([A-Za-z]{2,5}-)?[A-Za-z]{2,5}-\\d{2}-\\d{2}"
```

La variable `regex_report_id` sera utilisée plusieurs fois dans ce document. 

On liste les rapports de laboratoire présents dans le dossier `03-Labo/Results Reports`.

```{r}
reports_path <- list.files(
    "C:/Users/VissaultS/Documents/03-Labo/Results Reports", 
    pattern = "*.pdf|*.docx|*.doc", recursive = TRUE, full.names = TRUE
)

# On extrait les identifiants des rapports du nom du fichier
report_id <- stringr::str_extract(reports_path, regex_report_id)

# On obtient la signature du fichier, ca va être pratique pour detecter les fichiers dupliqués même si le nom du fichier est différent.
file_hash <- tools::md5sum(reports_path)

# On extrait l'extension du fichier
file_ext <- reports_path |> 
    strsplit("[.]") |> 
    purrr::map_chr(\(e) return(e[2]))

# On compose un tableau avec l'ensemble de ces informations
reports <- data.frame(
        path = reports_path, 
        id = report_id, 
        hash = file_hash, 
        ext = file_ext
    ) |> tibble::as_tibble()
```

Note: `tools::md5sum` permet de générer une signature unique propre au fichier. Ainsi deux fichiers identiques dans le contenu mais avec des noms différents pourront être identifié comme des duplicats.

Voici la liste des fichiers identiques dans le dossier `03-Labo/Results Reports`.

```{R, results='asis'}
reports_dup <- reports |> 
    tibble::as_tibble() |>
    janitor::get_dupes(-c(path)) |>
    dplyr::select(-hash)

reports_dup |> knitr::kable()
```

On selectionne le premier rapport en se basant sur le id (ex. BMK-PFC-23-01) pour éliminer les rapports dupliqués pour la suite de l'analyse. On s'assure de selectionner préférablement les pdfs si on dispose d'un docx et d'un document pdf pour le même identifiant de rapport de laboratoire.

```{r}
reports <- reports |> 
    # On retire les rapports qui sont dupliqués
    dplyr::group_by(hash) |>
    dplyr::slice(1) |>
    dplyr::ungroup() |>
    # Si plusieurs extension de fichiers, on selectionne ceux en PDF préférablement, sinon .docx, sinon .doc en dernier recours.
    dplyr::group_split(id) |>
    purrr::map(\(g){
        g |> dplyr::arrange(factor(ext, levels = c('pdf', 'docx', 'doc'))) |>
        dplyr::slice(1)
    }) |>
    dplyr::bind_rows()
```

Quelques rapports de laboratoire demeurent au format doc et docx.

```{R, results='asis'}
docs <- reports |> dplyr::filter(ext %in% c('doc', 'docx')) 
docs |> knitr::kable()
```

Afin de faciliter l'extraction des métadonnées par programmation, on convertit les fichiers .doc et .docx en pdf.

## Convertion des documents Word en pdf

Cette étape a été complété manuellement.

## Extraire les métadonnées du rapport

Nous souhaitons générer une liste de tous les projets basée sur les `r nrow(reports)` rapports de laboratoire stockés dans le dossier `03-Labo/Comptes rendus` de résultats. La première page de chaque rapport de laboratoire contient toutes les informations pertinentes pour produire cette liste.

Pour chaque rapport, nous vérifions s'il s'agit d'une image ou non. Si le rapport est une image, nous devons utiliser une reconnaissance optique de caractères (OCR) afin d'extraire le texte de la première page et d'obtenir toutes les métadonnées pertinentes. Si c'est un pdf ou un fichier word, nous importons la première page du document.

```{R, eval = FALSE}
# On détect si le document est une image
reports <- reports |> dplyr::mutate(
    filename = basename(path),
    is_image = purrr::map2_lgl(path, ext, \(p, e) {
        if(e == "pdf"){
            out <- pdftools::pdf_text(p)
            !all(nchar(out) > 15)
        } else {
            FALSE
        }
    })
)

# On extrait le texte par OCR si c'est une image
frontpages <- purrr::map2_vec(reports$path, reports$is_image, \(p, i) {
        ifelse(isTRUE(i), 
            pdftools::pdf_ocr_text(pdf = p, pages = 1),
            pdftools::pdf_text(pdf = p)[[1]]
        )
    }) |> tolower()
```

Une fois le texte de la première page isolé, on applique une série d'opération d'extractions de texte à partir de la position de mots clés. On isole ainsi le titre du projet, l'ID du projet, la date etc.

```{R, eval = FALSE}
project_id <- purrr::map_vec(frontpages, \(f){
    stringr::str_extract(f, "(?<=(project: |project |projects|projet :)).*(?=\n)")
}) |> 
    toupper() |> 
    stringr::word(1) |> 
    stringr::str_replace_all("[.,]", "") |>
    stringr::str_trim() |>
    dplyr::na_if("")

project_leader <- purrr::map_vec(frontpages, \(f){
        stringr::str_extract(f, "(?<=(project leader: |project leader |project manager: |manager: |study leader: |nom du requérant :)).*(?=\n)")
    }) |> 
    stringr::str_replace_all(c("[_|:]" = "", "[:digit:]" = "", "[.]$" = "")) |> 
    stringr::str_to_title() |>
    stringr::str_trim()

project_dates <- frontpages |>
    purrr::map_vec(\(f){
        dates <- stringr::str_extract(f, "\\d{4}-\\d{2}-\\d{2}")
        if(is.na(dates)) {
            dates <- stringr::str_extract(f, "(?<=(date: )).*(?=\n)")
        }
        return(dates)
    }) 
        
reportsProject <- data.frame(
    report_id = reports$id, 
    report_access_path = stringr::str_replace_all(reports$path, "C:/Users/VissaultS/Documents", "Z:"), 
    project_id, project_leader, project_dates, project_title = NA
)
```

Le data.frame `reportsProject` est à la base du fichier "Z:\07-Données BD\BD_projects\projects_list_extract_25032024.xlsx".

## Valider l'existence de rapports de laboratoire dans le dossier `01-Projet et suivis`

On valide si certains de ces rapports ne se retrouvent pas dans le dossier `03-Labo/Comptes rendus`. Ces rapports pourraient potentiellement nous interressés.

```{R, result = "asis"}
files <- list.files(
    "C:/Users/VissaultS/Documents/01-Projets et suivis", 
    pattern = "*.pdf|*.docx|*.doc", recursive = TRUE, full.names = TRUE
)

potential_reports <- data.frame(file = files[which(stringr::str_detect(files, regex_report_id))])

potential_reports <- potential_reports |> dplyr::mutate(
    id = stringr::str_extract(file, regex_report_id) |> toupper(),
    in_lab_report_folder = !(id %in% reports$id)
) |> dplyr::arrange(in_lab_report_folder) |>
    dplyr::mutate(file = stringr::str_replace(file, "C:/Users/VissaultS/Documents/", "Z:"))
```