Informatique reproductible en R. Comment séparer le code et les données?

Très souvent, des calculs périodiques et la préparation d'un rapport consolidé sur les données autosuffisantes sont nécessaires. Ceux. en fonction des données stockées sous forme de fichiers. Il peut s'agir de données collectées à partir de sources ouvertes, de divers documents et tableaux Excel, de téléchargements à partir de systèmes d'entreprise. Les données brutes peuvent prendre plusieurs mégaoctets ou plusieurs gigaoctets. Les données peuvent être dépersonnalisées ou contenir des informations confidentielles. Dans le cas où le code de calcul est placé dans le référentiel, et que le travail est effectué par plusieurs personnes sur plusieurs ordinateurs, le problème se pose de maintenir la cohérence du code et des données. Dans le même temps, il est toujours nécessaire de garantir le respect des différents droits d'accès au code et aux données. Que faire?


Il s'agit d'une continuation de publications antérieures .


RStudio développe actuellement activement un package pinspour résoudre ce problème. Malheureusement, les solutions backend utilisées sont quelque peu impopulaires et coûteuses à utiliser dans l'immensité de notre pays. AWS, Azure, Google cloud ... pour tout ce que vous devez payer, pour le stockage et le trafic. AWS4 pinsne prend pas encore en charge l' authentification , donc le cloud Yandex est également en marge, bien qu'il ne soit pas gratuit.


D'un autre côté, les équipes d'analystes travaillant sur des tâches spécifiques sont généralement petites (pas plus de 5 à 10 personnes). Beaucoup utilisent Google Drive, One Drive, etc., dans un format payant ou gratuit. Pourquoi ne pas profiter des ressources déjà acquises? Vous trouverez ci-dessous l'un des workflows possibles.


Plan global


  1. Les calculs doivent être effectués localement sur la machine, ce qui signifie que la machine doit avoir une réplique réelle de toutes les données nécessaires aux calculs.
  2. Le code doit être sous contrôle de version. Les données ne doivent en aucun cas y entrer (volume potentiel et confidentialité). Nous stockons la réplique de données soit dans un dossier séparé du projet (y compris dans .gitignore), soit dans un répertoire externe relatif au projet.
  3. La base de données sera stockée sur Google Drive. Nous y plaçons les droits d'accès aux répertoires.

Cela reste le cas pour les petits. Il est nécessaire d'implémenter la fonctionnalité de synchronisation de la réplique de données locale avec le cloud. L'autorisation et l'authentification sont fournies par Google.


Voici le code.


library(googledrive)
library(memoise)
#    google disk
drive_user()
updateGdCache(here::here("data/"), cloud_folder = "XXX___jZnIW3jdkbdxK0iazx7t63Dc")

Fonction de synchronisation du cache
updateGdCache <- function(local_folder, cloud_folder){
  #     
  cache_fname <- "gdrive_sig.Rds"
  # 0.  memoise     
  getGdriveFolder <- memoise(function(gdrive_folder){
    drive_ls(as_id(gdrive_folder), recursive = FALSE)
  })

  # 1.        
  cloud_gdrive_sig <- purrr::possibly(getGdriveFolder, NULL)(cloud_folder)
  #          ,     
  if(is.null(cloud_gdrive_sig)) {
    message("Some Google Drive issues happened. Can't update cache")
    return()
  }
  # 2.       
  fdir <- if(fs::is_dir(local_folder)) local_folder else fs::path_dir(local_folder)

  # 3.       
  local_files <- fs::dir_ls(fdir, recurse = FALSE) %>%
    fs::path_file()

  # 4.        
  local_gdrive_sig <- purrr::possibly(readRDS, NULL, quiet = TRUE)(fs::path(fdir, cache_fname))
  if(is.null(local_gdrive_sig)){
    #    ,   ,     
    #  ,   
    local_gdrive_sig <- cloud_gdrive_sig %>%
      dplyr::filter(row_number() == -1)
  }
  #         
  local_gdrive_sig <- local_gdrive_sig %>%
    dplyr::filter(name %in% local_files)

  # 5.      ,    ,   
  #  ,       
  reconcile_tbl <- cloud_gdrive_sig %>%
    dplyr::rename(drive_resource_cloud = drive_resource) %>%
    dplyr::left_join(local_gdrive_sig, by = c("name", "id")) %>%
    tidyr::hoist(drive_resource_cloud, cloud_modified_time = "modifiedTime") %>%
    tidyr::hoist(drive_resource, local_modified_time = "modifiedTime") %>%
    # TODO:   ,       
    #       = NA
    dplyr::mutate(not_in_sync = is.na(local_modified_time) | cloud_modified_time != local_modified_time)

  # 6.    
  syncFile <- function(fpath, id){
    res <- purrr::possibly(drive_download, otherwise = NULL)(as_id(id), path = fpath, overwrite = TRUE, verbose = TRUE)
    ifelse(is.null(res), FALSE, TRUE)
  }
  #  ,        ,   
  sync_gdrive_sig <- reconcile_tbl %>%
    dplyr::filter(not_in_sync == TRUE) %>%
    dplyr::mutate(fpath = fs::path(fdir, name)) %>%
    dplyr::mutate(sync_status = purrr::map2_lgl(fpath, id, syncFile)) %>%
    dplyr::select(name, id, sync_status)

  # 7.      ,   
  #   
  cloud_gdrive_sig %>%
    #   
    dplyr::anti_join(dplyr::filter(sync_gdrive_sig, sync_status == FALSE), by = c("name", "id")) %>%
    saveRDS(fs::path(fdir, cache_fname))
}

Spécifiez l'identifiant du dossier dans google drive comme chemin, vous pouvez le prendre dans la barre d'adresse du navigateur. L'identifiant restera inchangé même si le dossier est déplacé dans le lecteur.



Simple, compact, pratique et gratuit.


Quelques commentaires


  1. Il y a des problèmes avec l'encodage pour la gargleversion 0.4.0. Il est nécessaire de charger la version dev. Plus de détails ici .
  2. Il y a des problèmes avec l'autorisation sur RStudio Server «Impossible d'autoriser depuis RStudio Server # 79 {Closed}» , mais des idées pour une solution de contournement peuvent être trouvées ici .

Publication précédente - «La programmation et l'arbre de Noël, peuvent-ils être combinés?» .

Source: https://habr.com/ru/post/undefined/


All Articles