unit-testing - test - tdd
¿Qué paquetes básicos debe tener un desarrollador profesional de R, y por qué? (3)
¿Cuáles son las utilidades específicas que pueden ayudar a los desarrolladores de R a codificar y depurar de manera más eficiente?
Estoy buscando establecer un entorno de desarrollo R y me gustaría obtener una descripción general de las herramientas que me serían útiles para diseñar una infraestructura de prueba de unidades con cobertura de código, depuración, generación de archivos de paquete y archivos de ayuda y tal vez modelado UML.
Nota: justifique sus respuestas con motivos y ejemplos basados en su experiencia con las herramientas que recomienda. No solo enlaces .
Relacionado
Como recuerdo, esto se ha preguntado antes y mi respuesta sigue siendo la misma: Emacs.
Emacs puede
- hacer casi cualquier cosa que quiera hacer con R gracias a ESS , que incluye
- ejecución de código de varios fragmentos (línea, región, función, búfer, ...)
- inspección de espacios de trabajo,
- visualización de variables,
- múltiples sesiones R y fácil cambio entre ellas
- modo de transcripción para volver a ejecutar (partes de) sesiones anteriores
- acceso al sistema de ayuda
- y mucho más
- maneja Latex con facilidad similar a través del modo AucTex, que ayuda a Sweave para R
- tiene modos para cualquier otro lenguaje de programación que combine con R, ya sea C / C ++, Python, shell, SQL, ... cubriendo sangría automática y resaltado de color
- puede acceder a las bases de datos con el modo sql- *
- puede trabajar de forma remota con el modo vagabundo: acceder a los archivos remotos como si fueran locales (usa ssh / scp)
- puede ejecutarse como daemon, lo que lo hace con estado para que pueda volver a conectarse a su misma sesión de Emacs, ya sea en la estación de trabajo bajo X11 (o equivalente) o de forma remota a través de ssh (con o sin X11) o pantalla.
- tiene org-mode , que junto con babel, proporciona una poderosa alternativa de sweave como se discute en este documento sobre las aplicaciones de flujo de trabajo para científicos (sociales)
- puede ejecutar un shell a través de
Mx shell
y / oMx eshell
, tiene buena funcionalidad de acceso a directorios con el modo directo, tiene modo ssh para acceso remoto - interconecta todos los repositorios de código fuente con facilidad a través de modos específicos (por ejemplo, psvn para svn)
- es multiplataforma como R, por lo que tiene experiencias de interfaz de usuario similares en todos los sistemas operativos relevantes
- es ampliamente utilizado, ampliamente disponible y en desarrollo activo tanto para código como para extensiones, consulte el sitio emacswiki.org para este último
-
<tongueInCheek>
no es Eclipse y no requiere Java</tongueInCheek>
Por supuesto, puede combinarlo con los paquetes CRAN que desee: RUnit o testthat, los diferentes paquetes de soporte de creación de perfiles, el paquete de depuración, ...
Herramientas adicionales que son útiles:
-
R CMD check
realmente es tu amigo, ya que esto es lo que CRAN usa para decidir si estás "adentro o afuera"; úsala y confía en ella - el directorio
tests/
puede ofrecer una versión simplificada de las pruebas unitarias guardando para ser comparado con la salida (de una ejecución previa deR CMD check
), esto es útil, pero las pruebas unitarias correctas son mejores - particularmente para paquetes con código de objeto, prefiero lanzar nuevas sesiones R y littler hace fácil:
r -lfoo -e''bar(1, "ab")''
inicia una sesión R, carga el paquetefoo
y evalúa la expresión dada ( aquí unabar()
funcionesbar()
con dos argumentos). Esto, combinado conR CMD INSTALL
, proporciona un ciclo de prueba completo.
El conocimiento de, y la capacidad de usar, las herramientas básicas de depuración R es un primer paso esencial para aprender a depurar rápidamente el código R. Si sabe cómo usar las herramientas básicas, puede depurar el código en cualquier lugar sin tener que necesitar todas las herramientas adicionales proporcionadas en los paquetes adicionales.
traceback()
permite ver la pila de llamadas que conduce a un error
foo <- function(x) {
d <- bar(x)
x[1]
}
bar <- function(x) {
stopifnot(is.matrix(x))
dim(x)
}
foo(1:10)
traceback()
rendimientos:
> foo(1:10)
Error: is.matrix(x) is not TRUE
> traceback()
4: stop(paste(ch, " is not ", if (length(r) > 1L) "all ", "TRUE",
sep = ""), call. = FALSE)
3: stopifnot(is.matrix(x))
2: bar(x)
1: foo(1:10)
Entonces, podemos ver claramente que el error ocurrió en la bar()
funciones bar()
; hemos reducido el alcance de la búsqueda de errores. Pero, ¿y si el código genera advertencias, no errores? Eso se puede manejar convirtiendo las advertencias en errores a través de la opción de warn
:
options(warn = 2)
convertirá las advertencias en errores. A continuación, puede usar traceback()
para rastrearlos.
Vinculado a esto, conseguir que R se recupere de un error en el código para que pueda depurar qué salió mal. options(error = recover)
nos arrojará a un marco de depuración cada vez que se presente un error:
> options(error = recover)
> foo(1:10)
Error: is.matrix(x) is not TRUE
Enter a frame number, or 0 to exit
1: foo(1:10)
2: bar(x)
3: stopifnot(is.matrix(x))
Selection: 2
Called from: bar(x)
Browse[1]> x
[1] 1 2 3 4 5 6 7 8 9 10
Browse[1]> is.matrix(x)
[1] FALSE
Como ve, podemos colocarnos en cada cuadro de la pila de llamadas y ver cómo se llamaron las funciones, cuáles son los argumentos, etc. En el ejemplo anterior, vemos que a bar()
se le pasó un vector, no una matriz, de ahí el error. options(error = NULL)
restablece este comportamiento a normal.
Otra función clave es trace()
, que le permite insertar llamadas de depuración en una función existente. El beneficio de esto es que puede decirle a R que depure desde una línea particular en la fuente:
> x <- 1:10; y <- rnorm(10)
> trace(lm, tracer = browser, at = 10) ## debug from line 10 of the source
Tracing function "lm" in package "stats"
[1] "lm"
> lm(y ~ x)
Tracing lm(y ~ x) step 10
Called from: eval(expr, envir, enclos)
Browse[1]> n ## must press n <return> to get the next line step
debug: mf <- eval(mf, parent.frame())
Browse[2]>
debug: if (method == "model.frame") return(mf) else if (method != "qr") warning(gettextf("method = ''%s'' is not supported. Using ''qr''",
method), domain = NA)
Browse[2]>
debug: if (method != "qr") warning(gettextf("method = ''%s'' is not supported. Using ''qr''",
method), domain = NA)
Browse[2]>
debug: NULL
Browse[2]> Q
> untrace(lm)
Untracing function "lm" in package "stats"
Esto le permite insertar las llamadas de depuración en el punto correcto del código sin tener que pasar por las llamadas a funciones anteriores.
Si desea pasar por una función mientras se está ejecutando, entonces la debug(foo)
activará el depurador para la función foo()
, mientras que undebug(foo)
desactivará el depurador.
Un punto clave acerca de estas opciones es que no he necesitado modificar / editar ningún código fuente para insertar llamadas de depuración, etc. Puedo probar cosas y ver cuál es el problema directamente desde la sesión donde ocurrió el error.
Para obtener una versión diferente de la depuración en R, consulte el paquete de debug Mark Bravington en CRAN
He escrito demasiados paquetes, así que para mantener las cosas manejables he invertido mucho tiempo en paquetes de infraestructura: paquetes que me ayudan a hacer que mi código sea más robusto y ayudar a que otros lo usen más fácilmente. Éstas incluyen:
roxygen2
(con Manuel Eugster y Peter Danenberg), que le permite mantener la documentación junto a la función que documenta, lo que hace que sea más probable que la mantenga actualizada.roxygen2
también tiene una serie de características nuevas diseñadas para minimizar la duplicación de documentación: plantillas (@template
), herencia de parámetros (@inheritParams
) y familias de funciones (@family
), por nombrar algunas.testthat
automatiza la prueba de mi código. Esto es cada vez más importante ya que tengo cada vez menos tiempo para programar: las pruebas automáticas recuerdan cómo debería funcionar la función, incluso cuando no lo hago.devtools
automatiza muchas tareas de desarrollo comunes (como mencionó Andrie). El objetivo final dedevtools
es que actúe como laR CMD check
que se ejecuta continuamente en segundo plano y le notifica a la instancia de que algo va mal.profr
, particularmente el explorador interactivo no publicado, me facilita encontrar cuellos de botella en mi código.helpr
(con Barret Schloerke), que pronto impulsará http://had.co.nz/ggplot2 , proporciona una elegante interfaz html para la documentación de R.
Funciones R útiles:
-
apropos
: siempre me olvido de los nombres de las funciones útiles, y aapropos
me ayuda a encontrarlas, incluso si solo recuerdo un fragmento
Fuera de R:
Uso textmate para editar archivos R (y otros), pero no creo que sea realmente tan importante. Elija uno y aprenda todos sus rincones y grietas.
Dedica algo de tiempo para aprender la línea de comando. Cualquier cosa que pueda hacer para automatizar cualquier parte de su flujo de trabajo dará sus frutos a largo plazo. Ejecutando R desde la línea de comandos lleva a un proceso natural donde cada proyecto tiene su propia instancia de R; A menudo tengo 2-5 instancias de R funcionando a la vez.
Usa control de versiones Me gusta
git
y github . Una vez más, no importa exactamente qué sistema uses, ¡pero domínalo!
Cosas que deseo que R tenga:
- herramientas de cobertura de código
- un marco de gestión de dependencia como rake o jake
- mejores herramientas de generación de perfiles de memoria
- un estándar de metadatos para describir marcos de datos (y otras fuentes de datos)
- mejores herramientas para describir y representar tablas en una variedad de formatos de salida
- un paquete para la representación de rebajas