La documentación dice
vapply
es similar asapply
, pero tiene un tipo de valor de retorno preespecificado, por lo que puede ser más seguro [...] de usar.
¿Podría explicar por qué en general es más seguro, quizás proporcionando ejemplos?
PD: Sé la respuesta y ya tiendo a evitarla sapply
. Solo desearía que hubiera una buena respuesta aquí en SO para poder señalarla a mis compañeros de trabajo. Por favor, no responda "lea el manual".
Respuestas:
Como ya se ha señalado,
vapply
hace dos cosas:El segundo punto es la mayor ventaja, ya que ayuda a detectar errores antes de que sucedan y conduce a un código más robusto. Esta verificación del valor de retorno se puede hacer por separado usando
sapply
seguido destopifnot
para asegurarse de que los valores de retorno sean consistentes con lo que esperaba, perovapply
es un poco más fácil (si es más limitado, ya que el código de verificación de errores personalizado podría verificar valores dentro de los límites, etc. ).Este es un ejemplo de
vapply
cómo garantizar que su resultado sea el esperado. Esto es paralelo a algo en lo que estaba trabajando mientras raspaba PDF, dondefindD
usaría unregexpara hacer coincidir un patrón en los datos de texto sin procesar (por ejemplo, tendría una listasplit
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 orden y habría dos direcciones para un entidad, que causó 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 programador es cambiar su forma de pensar de "los errores son molestos" a "los errores son mi amigo".
Entradas de longitud cero
Un punto relacionado es que si la longitud de entrada es cero,
sapply
siempre devolverá una lista vacía, independientemente del tipo de entrada. Comparar: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
, tiene la garantía de tener un tipo particular de salida, por lo que no necesita escribir comprobaciones adicionales para entradas de longitud cero.Benchmarks
vapply
puede ser un poco más rápido porque ya sabe en qué formato debería esperar los resultados.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)
fuente
Las pulsaciones de teclas adicionales involucradas
vapply
podrían ahorrarle tiempo al depurar resultados confusos más adelante. Si la función a la que está llamando puede devolver diferentes tipos de datos,vapply
ciertamente debería usarse.Un ejemplo que me viene a la mente estaría
sqlQuery
en elRODBC
paquete. Si hay un error al ejecutar una consulta, esta función devuelve uncharacter
vector con el mensaje. Entonces, por ejemplo, digamos que está tratando de iterar sobre un vector de nombres de tablastnames
y seleccione el valor máximo de la columna numérica 'NumCol' en cada tabla con:sapply(tnames, function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]])
Si todos los nombres de las tablas son válidos, esto resultaría en un
numeric
vector. Pero si uno de los nombres de las tablas cambia en la base de datos y la consulta falla, los resultados se convertirán en modocharacter
. Sin embargo, usarvapply
conFUN.VALUE=numeric(1)
detendrá el error aquí y evitará que aparezca en algún lugar de la línea, o peor aún, no en absoluto.fuente
Si siempre quiere que su resultado sea algo en particular ... por ejemplo, un vector lógico.
vapply
se asegura de que esto suceda, perosapply
no necesariamente.a<-vapply(NULL, is.factor, FUN.VALUE=logical(1)) b<-sapply(NULL, is.factor) is.logical(a) is.logical(b)
fuente
logical(1)
en este caso, ya que FALSE parece que establece una opción en "OFF" en lugar de especificar un tipo