img - R estilo de escritura-requieren vs.
tags$img shiny (2)
Bien, todos estamos familiarizados con el operador de doble colon en R. Cuando estoy a punto de escribir alguna función, utilizo require(<pkgname>)
, pero siempre pensé en usar ::
lugar. El uso de require
en funciones personalizadas es una práctica mejor que la library
, ya que require
advertencias de devolución y FALSE
, a diferencia de la library
, que devuelve un error si proporciona un nombre de paquete inexistente.
Por otro lado, ::
operator obtiene la variable del paquete, mientras que require
carga completa del paquete (al menos eso espero), por lo que las diferencias de velocidad fueron lo primero que me vino a la mente. ::
debe ser más rápido que lo require
.
E hice un análisis para verificar que: he escrito dos funciones simples que cargan la función read.systat
de foreign
paquete foreign
, con require
y ::
respectivamente, por lo tanto, importe el conjunto de datos Iris.syd
que se envía con foreign
paquete foreign
, funciones replicadas 1000 veces cada uno (lo que fue descaradamente arbitrario), y ... aplastó algunos números.
Extrañamente (o no) encontré diferencias significativas en términos de CPU de usuario y tiempo transcurrido, mientras que no hubo diferencias significativas en términos de CPU de sistema. Y aún más extraña conclusión: ::
es en realidad más lento! La documentación para ::
es muy contundente, y solo mirando las fuentes es obvio que ::
debería funcionar mejor!
exigir
#!/usr/local/bin/r
## with require
fn1 <- function() {
require(foreign)
read.systat("Iris.syd", to.data.frame=TRUE)
}
## times
n <- 1e3
sink("require.txt")
print(t(replicate(n, system.time(fn1()))))
sink()
doble colon
#!/usr/local/bin/r
## with ::
fn2 <- function() {
foreign::read.systat("Iris.syd", to.data.frame=TRUE)
}
## times
n <- 1e3
sink("double_colon.txt")
print(t(replicate(n, system.time(fn2()))))
sink()
Agarra los datos CSV here . Algunas estadísticas:
user CPU: W = 475366 p-value = 0.04738 MRr = 975.866 MRc = 1025.134
system CPU: W = 503312.5 p-value = 0.7305 MRr = 1003.8125 MRc = 997.1875
elapsed time: W = 403299.5 p-value < 2.2e-16 MRr = 903.7995 MRc = 1097.2005
MRr es el rango medio para require
, MRc ibid para ::
. Debo haber hecho algo mal aquí. Simplemente no tiene ningún sentido ... ¡El tiempo de ejecución para ::
parece mucho más rápido! Puede que haya arruinado algo, no deberías descartar esa opción ...
Bien ... he perdido el tiempo para ver que hay alguna diferencia, y realicé un análisis completamente inútil, así que, volviendo a la pregunta:
" ¿Por qué debería preferirse require
sobre ::
al escribir una función? "
=)
"¿Por qué debería preferirse requerir sobre :: al escribir una función?"
Generalmente prefiero require
debido al buen valor de retorno VERDADERO / FALSO que me permite lidiar con la posibilidad de que el paquete no esté disponible por adelantado antes de ingresar al código. Acceda lo antes posible en lugar de a mitad de su análisis.
Solo uso ::
cuando necesito asegurarme de que estoy usando la versión correcta de una función, no una versión de algún otro paquete que esté ocultando el nombre.
Por otro lado, :: operator obtiene la variable del paquete, mientras que requiere una carga completa del paquete (al menos eso espero), por lo que las diferencias de velocidad fueron lo primero que me vino a la mente. :: debe ser más rápido que lo requerido.
Creo que puede estar ignorando los efectos de la carga lenta que usa el paquete foreign
acuerdo con la primera página de su manual . Esencialmente, los paquetes que utilizan la carga diferida retrasan la carga de objetos, como las funciones, hasta que los objetos son llamados por primera vez. Por lo tanto, su argumento de que " ::
debe ser más rápido de lo que se requiere" no es necesariamente verdadero, ya que no se está cargando todo su contenido en la memoria cuando se adjunta. Para detalles completos sobre la carga perezosa, vea el artículo del Prof. Ripley en RNews, Volumen 4, Número 2.
Dado que el tiempo para cargar un paquete es casi siempre pequeño en comparación con el tiempo que dedica a tratar de averiguar de qué trata el código que escribió hace seis meses, en este caso lo más importante es codificar para mayor claridad.
Para los scripts, tener una llamada para require
o una library
al inicio le permite saber qué paquetes necesita de inmediato.
De manera similar, llamar a require
(o un envoltorio como requirePackage
en Hmisc
o try_require
en ggplot2
) al inicio de una función es la forma más inequívoca de mostrar que necesita usar ese paquete.
::
debe reservarse para los casos en los que tenga conflictos de nombres entre paquetes: compare, por ejemplo,
Hmisc::is.discrete
y
plyr::is.discrete