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

В документации говорится:

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

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


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

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

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

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

Вот пример vapply гарантирующий, что ваш результат будет таким, как ожидалось. Это findD то, над чем я только что работал, в то время как PDF- findD , где 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) 
  • Добавление столбца, содержащего значение bin другого столбца
  • Как вы используете «<< -» (присвоение области охвата) в R?
  • Транспонирование / изменение формы данных без «timevar» от длинного до широкоформатного
  • Как преобразовать коэффициент в integer \ numeric без потери информации?
  • Передайте имя столбца data.frame в функцию
  • Оценить выражение, данное как строка
  • Как преобразовать Блестящее приложение, состоящее из нескольких файлов, в легкоansible и воспроизводимый пример Shiny?
  • Количество строк в каждой группе
  • Как создать список фреймов данных?
  • Как сделать отличный R воспроизводимый пример
  • Как вы конкретно заказываете ось ggplot2 x вместо алфавитного порядка?
  • Interesting Posts
    Давайте будем гением компьютера.