Computación reproducible en R. ¿Cómo separar el código y los datos?

Muy a menudo existe la necesidad de cálculos periódicos y la preparación de un informe consolidado sobre datos autosuficientes. Aquellos. de acuerdo con los datos que se almacenan como archivos. Estos pueden ser datos recopilados de fuentes abiertas, diversos documentos y tablas de Excel, descargas de sistemas corporativos. Los datos sin procesar pueden ocupar varios megabytes o varios gigabytes. Los datos pueden ser despersonalizados o contener información confidencial. En el caso en que el código de cálculo se coloca en el repositorio, y el trabajo lo lleva a cabo más de una persona en más de una computadora, surge el problema de mantener la consistencia del código y los datos. Al mismo tiempo, aún es necesario garantizar el cumplimiento de los diferentes derechos de acceso al código y los datos. ¿Qué hacer?


Es una continuación de publicaciones anteriores .


RStudio ahora está desarrollando activamente un paquete pinspara resolver este problema. Desafortunadamente, las soluciones de backend utilizadas son algo impopulares y caras de usar en la inmensidad de nuestro país. AWS, Azure, Google cloud ... por cada uno que tiene que pagar, por almacenamiento y tráfico. AWS4 pinsaún no es compatible con la autenticación , por lo que Yandex Cloud también está al margen, aunque no es gratuito.


Por otro lado, los equipos de analistas que trabajan en tareas específicas suelen ser pequeños (no más de 5-10 personas). Muchos usan Google Drive, One Drive, etc., en un formato pago o gratuito. ¿Por qué no aprovechar los recursos ya adquiridos? A continuación se muestra uno de los posibles flujos de trabajo.


Plan General


  1. Los cálculos deben realizarse localmente en la máquina, lo que significa que la máquina debe tener una réplica real de todos los datos necesarios para los cálculos.
  2. El código debe estar bajo control de versiones. Los datos no deben incluirse de ninguna manera (volumen potencial y confidencialidad). Almacenaremos la réplica de datos en una carpeta separada en el proyecto (incluida en .gitignore) o en un directorio externo relativo al proyecto.
  3. El maestro de datos será almacenado por Google Drive. Colocamos los derechos para acceder a los directorios en él.

Sigue siendo el caso para los pequeños. Es necesario implementar la funcionalidad de sincronización de la réplica de datos local con la nube. La autorización y autenticación son proporcionadas por google.


Debajo está el código.


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

Función para sincronización de caché
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))
}

Especifique el identificador de carpeta en Google Drive como la ruta, puede tomarlo de la barra de direcciones del navegador. El identificador permanecerá sin cambios incluso si la carpeta se mueve en la unidad.



Simple, compacto, conveniente y gratuito.


Par de comentarios


  1. Hay problemas con la codificación para la gargleversión 0.4.0. Es necesario cargar la versión de desarrollo. Más detalles aquí .
  2. Hay problemas con la autorización en RStudio Server "No se puede autorizar desde RStudio Server # 79 {Cerrado}" , pero las ideas para una solución alternativa se pueden encontrar aquí .

Publicación anterior: "La programación y el árbol de Navidad, ¿se pueden combinar?" .

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


All Articles