Quienes trabajan con R son conscientes de que el lenguaje se diseñó originalmente como una herramienta para el trabajo interactivo. Naturalmente, los métodos convenientes para la aplicación paso a paso basada en la consola por una persona que está inmersa en el tema resultan inadecuados para crear una aplicación para el usuario final. La capacidad de obtener diagnósticos detallados inmediatamente después del hecho de un error, examinar todas las variables y trazas, ejecutar elementos de código manualmente (posiblemente cambiando parcialmente las variables): todo esto no estará disponible cuando la aplicación R esté fuera de línea en un entorno empresarial. (decimos R, nos referimos básicamente a aplicaciones web brillantes).
Sin embargo, no todo es tan malo. El entorno R (paquetes y enfoques) ha evolucionado tanto que una serie de trucos muy simples pueden resolver con elegancia el problema de garantizar la estabilidad y la fiabilidad de las aplicaciones del usuario. Algunos de ellos se describirán a continuación.
Es una continuación de publicaciones anteriores .
¿Cuál es la dificultad de la tarea?
La gama principal de tareas para las que se usa a menudo R es el procesamiento de datos diversos. E incluso un algoritmo completamente depurado, presentado en todos los lados mediante pruebas y completamente documentado, puede descomponerse fácilmente y dar una maldita cosa si obtiene datos torcidos en su entrada.
Los datos se pueden ingresar desde otros sistemas de información, así como de los usuarios. Y, si en el primer caso es posible exigir el cumplimiento de la API e imponer restricciones muy estrictas a la estabilidad del flujo de información, entonces en el segundo caso no hay escapatoria de sorpresas. Una persona puede cometer un error y deslizar el archivo incorrecto, escribirlo incorrectamente. El 99% de los usuarios usan Excel en su trabajo y prefieren sacar el sistema con él, muchas páginas, con un formato astuto. En este caso, la tarea se vuelve aún más complicada. Incluso un documento visualmente válido puede parecer completamente absurdo desde el punto de vista de la máquina. Las fechas están dispersas (la famosa historia "el diseñador de Excel pensó que 1900 fue un año bisiesto, pero no lo fue" ). Los valores numéricos se almacenan como texto y tipografía. Celdas invisibles y fórmulas ocultas ... Y mucho más. En principio, es imposible prever todos los rastrillos posibles: no hay suficiente imaginación. ¿De qué vale que solo se dupliquen los registros en varias combinaciones con fuentes curvas?
Como consideración adicional, tomaremos lo siguiente:
El excelente documento "Una introducción a la limpieza de datos con R" describe el proceso de preparación preliminar de datos. Para otros pasos, destacamos la presencia de dos fases de validación: técnica y lógica.
- La validación técnica es verificar la exactitud de la fuente de datos. Estructura, tipos, indicadores cuantitativos.
- La validación lógica puede ser de varias etapas, llevada a cabo en el curso de los cálculos, y consiste en verificar la conformidad de ciertos elementos de datos o sus combinaciones con diversos requisitos lógicos.
- Una de las reglas básicas en el desarrollo de interfaces de usuario es la formación de los diagnósticos más completos en caso de errores del usuario. Es decir, si el usuario ya ha subido el archivo, entonces es necesario verificar que sea lo más correcto posible y dar un resumen completo con todos los errores (también es recomendable explicar qué está mal), y no bloquearse en el primer problema con un mensaje como "Entrada incorrecta value @ line 528493, pos 17 ”y requiere la descarga de un nuevo archivo con este error solucionado. Este enfoque le permite reducir significativamente el número de iteraciones para formar la fuente correcta y mejorar la calidad del resultado final.
Tecnologías y métodos de validación.
Vayamos desde el final. Hay varios paquetes para la validación lógica. En nuestra práctica, nos decidimos por los siguientes enfoques.
- Ya es un clásico
dplyr
. En casos simples, es conveniente simplemente dibujar una tubería con una serie de comprobaciones y análisis del resultado final. - El paquete de
validate
para verificar que los objetos técnicamente correctos cumplan con las reglas dadas.
Para la validación técnica, nos centramos en los siguientes enfoques:
- Paquete
checkmate
con una amplia gama de funciones rápidas para realizar una variedad de controles técnicos. - Trabajo explícito con excepciones "Depuración avanzada de R., manejo de condiciones y programación defensiva" , "Gestión avanzada de R. más allá de excepciones: condiciones y reinicios", tanto para llevar a cabo la validación completa en un solo paso, como para garantizar la estabilidad de la aplicación.
- Use envoltorios de
purr
para excepciones. Muy útil cuando se usa dentro de una tubería.
En el código desglosado en funciones, un elemento importante de la programación defensiva es verificar los parámetros de entrada y salida de las funciones. En el caso de idiomas con tipeo dinámico, la verificación de tipo debe hacerse de forma independiente. Para los tipos básicos, el paquete checkmate es ideal, especialmente sus qassert
qtest
\ qassert
. Para verificar data.frame
detuvimos en la siguiente construcción (verificar nombres y tipos). El truco para combinar el nombre y el tipo reduce el número de líneas en el cheque.
ff <- function(dataframe1, dataframe2){ # calledFun <- deparse(as.list(sys.call())[[1]]) tic("Calculating XYZ") # (class, typeof, Date ) list(dataframe1=c("name :: character", "val :: numeric", "ship_date :: Date"), dataframe2=c("out :: character", "label :: character")) %>% purrr::iwalk(~{ flog.info(glue::glue("Function {calledFun}: checking '{.y}' parameter with expected structure '{collapse(.x, sep=', ')}'")) rlang::eval_bare(rlang::sym(.y)) %>% assertDataFrame(min.rows=1, min.cols=length(.x)) %>% {assertSetEqual(.x, stri_join(names(.), map_chr(., class), sep=" :: "), .var.name=.y)} # {assertSubset(.x, stri_join(names(.), map_chr(., typeof), sep=" :: "))} }) … }
Como parte de la función de verificación de tipo, puede elegir un método a su gusto, de acuerdo con los datos esperados. Se eligió la class
porque es la que da la fecha como Date
, y no como un número (representación interna). La cuestión de determinar los tipos de datos se discute en gran detalle en el diálogo "Una encuesta exhaustiva de los tipos de cosas en R. 'mode' y 'class' y 'typeof' son insuficientes" .
assertSetEqual
o assertSubset
se seleccionan por razones de columnas coincidentes claras o el mínimo suficiente.
Para tareas prácticas, un conjunto tan pequeño cubre por completo la mayoría de las necesidades.
Publicación anterior: R como salvavidas para un administrador del sistema .