Почему "vapply" безопаснее, чем "sapply"?



в документации написано




vapply похож на sapply, но и предварительно указанный тип возвращаемого значения, поэтому он может быть безопаснее...] пустить в ход.




не могли бы Вы уточнить, почему это, как правило, безопаснее, возможно, приводя примеры?





P. S.: Я знаю ответ и я уже стремятся избежать sapply. Я просто хочу, чтобы здесь был хороший ответ, чтобы я мог указать на него своим коллегам. Пожалуйста, нет " прочитайте инструкцию" ответ.

675   3  

3 ответов:

как уже отмечалось, vapply делает две вещи:

  • небольшое улучшение скорости
  • улучшает согласованность, предоставляя ограниченные проверки типа возврата.

второй момент является большим преимуществом, так как это помогает поймать ошибки, прежде чем они произойдут, и приводит к более надежному коду. Эта проверка возвращаемого значения может быть выполнена отдельно с помощью sapply следовал по stopifnot чтобы убедиться, что возвращаемые значения соответствуют тому, что вы ожидали, но vapply немного проще (если более ограничено, так как пользовательский код проверки ошибок может проверять значения в пределах границ и т. д.).

вот пример vapply обеспечение вашего результата, как и ожидалось. Это параллели то, что я просто работал во время PDF выскабливания, где findD использовать выражение чтобы соответствовать шаблону в необработанных текстовых данных (например, у меня был бы список, который был split по сущности и регулярное выражение для сопоставления адресов внутри каждой сущности. Иногда PDF-файл был преобразован вне порядка, и для объекта будет два адреса, что вызвало плохую работу).

> 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

как я говорю своим студентам, часть того, чтобы стать программистом, меняет ваше мышление с "ошибки раздражают" на " ошибки-мой друг."

нулевой длины входных данных
Один связанный момент заключается в том, что если входная длина равна нулю,sapply всегда будет возвращать пустой список, независимо от типа входного сигнала. Сравните:

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)

С vapply, вы гарантированно имеете определенный тип вывода, поэтому вам не нужно писать дополнительные проверки для входов нулевой длины.

критерии

vapply может быть немного быстрее, потому что он уже знает, в каком формате следует ожидать результатов.

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)

autoplot

дополнительные ключевые штрихи, связанные с vapply может сэкономить вам время отладки запутанных результатов позже. Если вызываемая функция может возвращать различные типы данных, vapply безусловно, следует использовать.

один из примеров, который приходит на ум, будет sqlQuery на RODBC пакета. Если есть ошибка выполнения запроса, эта функция возвращает character вектор с сообщением. Так, например, предположим, что вы пытаетесь перебрать вектор имен таблиц tnames и выбираем максимальное значение из числового столбца 'NumCol' в каждой таблице с:

sapply(tnames, 
   function(tname) sqlQuery(cnxn, paste("SELECT MAX(NumCol) FROM", tname))[[1]])

если все имена таблиц действительны, это приведет к numeric вектор. Но если одно из имен таблиц изменится в базе данных и запрос завершится неудачно, результаты будут принудительно переведены в режим character. Используя vapply С FUN.VALUE=numeric(1), однако, остановит ошибку здесь и предотвратит ее появление где-то вниз по линии-- - или, что еще хуже, совсем нет.

Если вы всегда хотите, чтобы ваш результат был чем-то особенным...например, логический вектор. vapply гарантирует, что это произойдет, но sapply не обязательно это делать.

a<-vapply(NULL, is.factor, FUN.VALUE=logical(1))
b<-sapply(NULL, is.factor)

is.logical(a)
is.logical(b)

Comments

    Ничего не найдено.