Почему `vapply` безопаснее, чем` sapply`?
В документации говорится:
vapply
похож наsapply
, но имеет заданный тип возвращаемого значения, поэтому он может быть более безопасным […] для использования.
Не могли бы вы рассказать о том, почему это вообще безопаснее, может быть, примеры?
- Как мне обращаться с «пакетом ххх» не доступно (для R версии xyz)? Предупреждение?
- Удаление столбцов фрейма данных по имени
- Совокупность / суммирование нескольких переменных для каждой группы (например, сумма, среднее значение)
- Почему суммировать или мутировать не работать с group_by при загрузке `plyr` после` dplyr`?
- Импорт нескольких CSV-файлов в R
PS: Я знаю ответ, и я уже склонен избегать sapply
. Я просто хочу, чтобы здесь был хороший ответ, поэтому я могу указать на моих коллег. Пожалуйста, нет ответа «прочитать руководство».
- strptime, as.POSIXct и as.Date возвращают неожиданные NA
- R: Перестановки и комбинации с / без замены и для отдельных / неявных элементов / мультимножества
- Поиск всех позиций для нескольких элементов в векторе
- Ошибка в : цель присвоения расширяется до неязыкового объекта
- Раунд вверх от .5
- Как написать trycatch в R
- Как выполнить естественную сортировку?
- Нумерация строк внутри групп в кадре данных
Как уже отмечалось, 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)
Дополнительные нажатия клавиш, связанные с 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)