Есть ли причина, почему я должен использовать
map(<list-like-object>, function(x) <do stuff>)
вместо того
lapply(<list-like-object>, function(x) <do stuff>)
выходные данные должны быть такими же, а сделанные мной тесты, по-видимому, показывают, что lapply
это немного быстрее (это должно быть так, как map
необходимо для оценки всех нестандартных оценок).
Так есть ли причина, по которой в таких простых случаях мне стоит подумать о переходе на purrr::map
? Я не спрашиваю здесь о подобных своем или антипатиях о синтаксисе, другие функции обеспечиваются purrr и т.д., но строго о сравнении purrr::map
с lapply
предполагая , используя стандартную оценку, то есть map(<list-like-object>, function(x) <do stuff>)
. Есть ли какое-либо преимущество purrr::map
с точки зрения производительности, обработки исключений и т. Д.? Комментарии ниже предполагают, что это не так, но, возможно, кто-то мог бы уточнить немного больше?
tidyverse
хотя, вы можете извлечь выгоду из трубы%>%
и анонимных функций~ .x + 1
синтаксиса~{}
сокращение лямбда (с или без{}
печатей сделка для меня для простогоpurrr::map()
. Приведение типов в действиеpurrr::map_…()
удобны и менее тупы, чемvapply()
.purrr::map_df()
это супер дорогая функция, но она также упрощает код. Нет ничего плохого в том, чтобы придерживаться базы R[lsv]apply()
, хотя .purrr
вещи. Моя точка зрения заключается в следующем:tidyverse
отлично подходит для анализа / интерактивных / отчетов, а не для программирования. Если вам нужно использоватьlapply
илиmap
вы программируете, и однажды вы можете создать пакет. Тогда чем меньше зависимостей, тем лучше. Плюс: я иногда вижу людей, использующихmap
довольно туманный синтаксис после. И теперь, когда я вижу тестирование производительности: если вы привыкли кapply
семье: придерживайтесь этого.Ответы:
Если единственной функцией, которую вы используете от purrr, является
map()
, то нет, преимущества не являются существенными. Как указывает Рич Пауло, главное преимуществоmap()
- это помощники, которые позволяют писать компактный код для общих особых случаев:~ . + 1
эквивалентноfunction(x) x + 1
list("x", 1)
эквивалентноfunction(x) x[["x"]][[1]]
. Эти помощники являются более общими, чем[[
- см.?pluck
Подробности. Для rectangling данных , то.default
аргумент особенно полезно.Но большую часть времени вы не используете одну
*apply()
/map()
функцию, вы используете их несколько, и преимущество мурлыканья заключается в гораздо большей согласованности между функциями. Например:Первый аргумент
lapply()
- это данные; Первый аргументmapply()
- это функция. Первым аргументом для всех функций карты всегда являются данные.С помощью
vapply()
,sapply()
иmapply()
вы можете подавить имена на выходе с помощьюUSE.NAMES = FALSE
; ноlapply()
не имеет этого аргумента.Не существует единого способа передачи непротиворечивых аргументов в функцию mapper. Большинство функций используют,
...
ноmapply()
используютMoreArgs
(которые вы ожидаете вызватьMORE.ARGS
)Map()
,Filter()
иReduce()
ожидаете , что вы создадите новую анонимную функцию. В функциях карты константный аргумент всегда идет после имени функции.Почти каждая функция purrr является стабильной по типу: вы можете предсказать тип вывода исключительно из имени функции. Это не верно для
sapply()
илиmapply()
. Да, естьvapply()
; но нет эквивалента дляmapply()
.Вы можете подумать, что все эти второстепенные различия не важны (так же, как некоторые люди думают, что нет преимуществ перед строковыми регулярными выражениями R), но, по моему опыту, они вызывают ненужные трения при программировании (различные порядки аргументов, всегда используемые для отключения меня), и они затрудняют изучение методов функционального программирования, потому что помимо больших идей, вы также должны изучить кучу случайных деталей.
Purrr также заполняет некоторые удобные варианты карт, которые отсутствуют в базе R:
modify()
сохраняет тип данных, используемых[[<-
для изменения «на месте». В сочетании с_if
вариантом это позволяет (красивый IMO) код, такой какmodify_if(df, is.factor, as.character)
map2()
позволяет отображать одновременно поверхx
иy
. Это облегчает выражение идей, таких какmap2(models, datasets, predict)
imap()
позволяет отображать одновременноx
и его индексы (либо имена, либо позиции). Это облегчает (например) загрузку всехcsv
файлов в каталоге, добавляяfilename
столбец к каждому.walk()
возвращает свой ввод невидимым; и полезно, когда вы вызываете функцию из-за ее побочных эффектов (т.е. записи файлов на диск).Не говоря уже о других помощниках, как
safely()
иpartial()
.Лично я обнаружил, что когда я использую purrr, я могу писать функциональный код с меньшим трением и большей легкостью; это уменьшает разрыв между продумыванием идеи и ее реализацией. Но ваш пробег может отличаться; нет необходимости использовать purrr, если это не поможет вам.
Microbenchmarks
Да,
map()
немного медленнее, чемlapply()
. Но стоимость использованияmap()
илиlapply()
зависит от того, что вы отображаете, а не от затрат на выполнение цикла. Приведенный ниже микробенчмарк показывает, что стоимость поmap()
сравнению с нимlapply()
составляет около 40 нс на элемент, что вряд ли окажет существенное влияние на большинство кодов R.источник
mutate()
, я просто хотел простой пример без других deps.map_*
это то, что заставило меня загрузитьсяpurrr
во многих сценариях. Это помогло мне с некоторыми аспектами «потока управления» моего кода (stopifnot(is.data.frame(x))
).Сравнение
purrr
иlapply
сводится к удобству и скорости .1.
purrr::map
синтаксически удобнее, чем лапыизвлечь второй элемент списка
который как @F. Приве указал, так же, как:
с участием
lapply
нам нужно передать анонимную функцию ...
... или, как указал @RichScriven, мы передаем
[[
в качестве аргументаlapply
Поэтому, если вы обнаруживаете, что применяете функции ко многим спискам, использующим их
lapply
, и устали либо определять пользовательские функции, либо писать анонимные функции, удобство - одна из причин, по которой следует отдавать предпочтениеpurrr
.2. Специфичные для типа карты функции просто много строк кода
map_chr()
map_lgl()
map_int()
map_dbl()
map_df()
Каждая из этих картографических функций конкретного типа возвращает вектор, а не списки, возвращаемые
map()
иlapply()
. Если вы имеете дело с вложенными списками векторов, вы можете использовать эти специфичные для типа функции отображения, чтобы извлекать векторы напрямую и принудительно приводить векторы к векторам int, dbl, chr. Версия базы R будет выглядеть примерно такas.numeric(sapply(...))
,as.character(sapply(...))
и т.д.Эти
map_<type>
функции также имеют полезное качество, если они не могут вернуть атомный вектор указанного типа, они терпят неудачу. Это полезно при определении строгого потока управления, когда вы хотите, чтобы функция не работала, если она [каким-то образом] генерирует неправильный тип объекта.3. Удобство в стороне,
lapply
[немного] быстрее, чемmap
Используя
purrr
удобные функции, как @F. Приве отметил, что немного замедляет обработку. Давайте рассмотрим каждый из четырех случаев, которые я представил выше.И победителем становится....
В итоге, если вам нужна грубая скорость
base::lapply
(хотя она не намного быстрее)Для простого синтаксиса и выразительности:
purrr::map
Этот превосходный
purrr
учебник подчеркивает удобство отсутствия необходимости явной записи анонимных функций при использованииpurrr
и преимуществаmap
функций, специфичных для типа .источник
function(x) x[[2]]
вместо просто2
, это будет менее медленно. Все это дополнительное время связано с проверками, которыеlapply
не делают.[[
это функция. Вы можете сделатьlapply(list, "[[", 3)
.Если мы не рассматриваем аспекты вкуса (в противном случае этот вопрос должен быть закрыт) или согласованности синтаксиса, стиля и т. Д., Ответ - нет, особой причины для использования нет.
map
вместоlapply
или других вариантов семейства применений, таких как более строгиеvapply
.PS: Для тех людей, безвозмездно понижающих голосование, просто помните, что ОП писал:
Если вы не учитываете ни синтаксис, ни другие функциональные возможности
purrr
, нет особой причины для использованияmap
. Я используюpurrr
себя, и я в порядке с ответом Хэдли, но это иронично идет по тем самым вещам, которые ОП заявил заранее, он не спрашивал.источник