Como ya se ha señalado, vapply
hace dos cosas:
- mejora de la velocidad Poca
- mejora la consistencia proporcionando controles de tipo de retorno limitados.
El segundo punto es la mayor ventaja, ya que ayuda a detectar errores antes de que ocurran y conduce a un código más robusto. Esta verificación del valor de retorno se puede hacer por separado usando sapply
seguido de stopifnot
para asegurarse de que los valores devueltos sean consistentes con lo que esperaba, pero vapply
es un poco más fácil (si es más limitado, dado que el código de verificación de errores podría verificar valores dentro de límites , etc.)
Aquí hay un ejemplo de vapply
que garantiza que el resultado sea el esperado. Esto es paralelo a algo en lo que estaba trabajando al raspar PDF, donde findD
usaría un regex para que coincida con un patrón en datos de texto sin procesar (por ejemplo, tendría una lista que era split
por entidad y una expresión regular para hacer coincidir las direcciones dentro de cada entidad. Ocasionalmente, el PDF se había convertido fuera de servicio y habría dos direcciones para una entidad, lo que causaba maldad).
> input1 <- list(letters[1:5], letters[3:12], letters[c(5,2,4,7,1)])
> input2 <- list(letters[1:5], letters[3:12], letters[c(2,5,4,7,15,4)])
> findD <- function(x) x[x=="d"]
> sapply(input1, findD)
[1] "d" "d" "d"
> sapply(input2, findD)
[[1]]
[1] "d"
[[2]]
[1] "d"
[[3]]
[1] "d" "d"
> vapply(input1, findD, "")
[1] "d" "d" "d"
> vapply(input2, findD, "")
Error in vapply(input2, findD, "") : values must be length 1,
but FUN(X[[3]]) result is length 2
Como les digo a mis alumnos, parte de convertirse en un programador está cambiando su mentalidad de "errores son molestos" a "errores son mi amigo."
cero entradas de longitud
Un punto relacionado es que si la longitud de entrada es cero, sapply
siempre devolverá una lista vacía, sin importar el tipo de entrada. Compare:
sapply(1:5, identity)
## [1] 1 2 3 4 5
sapply(integer(), identity)
## list()
vapply(1:5, identity)
## [1] 1 2 3 4 5
vapply(integer(), identity)
## integer(0)
Con vapply
, usted está garantizado para tener un determinado tipo de producto, por lo que no tiene que escribir cheques adicionales para las entradas de longitud cero.
puntos de referencia
vapply
puede ser un poco más rápido porque ya sabe qué formato se debe esperar los resultados en.
input1.long <- rep(input1,10000)
library(microbenchmark)
m <- microbenchmark(
sapply(input1.long, findD),
vapply(input1.long, findD, "")
)
library(ggplot2)
library(taRifx) # autoplot.microbenchmark is moving to the microbenchmark package in the next release so this should be unnecessary soon
autoplot(m)
Es más predecible, lo que hace que el código sea menos ambiguo y más robusto. Particularmente en proyectos más grandes, por ejemplo, un paquete grande, esto es relevante. –
No es necesario el "P.S." ... simplemente responda usted mismo la pregunta. –
@KonradRudolph A veces, las notas al respecto pueden enfocar la pregunta y evitar las respuestas "RTFM". :-) –