apply и сконцентрироваться на purrr?
не можно, а нужно
В плане не навертят ли там в будущем что Хэдли сотоварищи?))
Я лично пока не вкурил ни purrr, ни magrittr :))) Хотя пару раз использовал.
Нет. В плане "есть ли смысл ворошить старьё, которое всё это время игнорировал, если новьё от Хэдли вроде как круче (на бумаге)".
Только в ознакомительных целях если))
чтобы читать код на гитхабе и пакетных функций
Ну я sapply на map_df заменил везде, где из папки файлы читались в датафрейм и он мне показался консистентнее и интуитивно понятнее.
Ну азы-то я знаю, но сам редко пользовал, т.к. какие-то нюансы синтаксиса плохо укладывались в голову. С функциями от Хэдли таких проблем нет. Они как по мне написаны более интуитивно понятно.
purrr сделан для разработки, а не только для интерактива. он ГАРАНТИРУЕТ типизацию возвращаемого результата! Это такой плюсище, что все остальное можно даже не плюсовать.
Очень советую пур посмотреть. Вот эти все фабрики функций делать, классно же. Идти от обратного, не на элементы применять одну функцию, а на один датафрейм применить kmeans с разным количеством центров и выбирать elbow методом потом оптимальный. Песня))
Так purrr от Хэдли. ну или с его благославения
Насчет интуитивной понятности... Как в этом сезоне arrange взаимодействует с группированным дата.фреймом? Какой результат будет у arrange после group_by? Это поведение менялось два раза, а потом я бросил следить
ну тут то постулируются правильные вещи: https://www.rstudio.com/resources/rstudioglobal-2021/maintaining-the-house-the-tidyverse-built/
"В больших знаниях большие горести". Я как не знал, так и не знаю. И живу счастливо.
Где-то в глубинах твоего кода что-то может неправильно сортироваться. Но это не точно)
не довелось встретить. хотя тестами вроде даже пытаемся обкладывать и run-time самопроверки добавлять.
Тесты конечно решают... Но просто в целом, когда после group_by поведение меняется , это грабли заботливо разложенные. Если человек пользуется только filter, mutate, summarize, то хорошо. А вот как с остальными глаголами взаимодействует group_by - не всегда угадаешь. У меня есть знакомая, которая в любой сложной ситуации пишет ungroup. И самое забавное, что это частенько работает)
она молодец. на воду дует.
Блин, прям сильно быстрее... Не ожидал
а вот вам любопытная граната: https://rpubs.com/wch/200398
Ну вот у меня обратная ситуация. Я на семейство apply всю жизнь как-то забивал. А тут вот задумался о том, что надо бы код поэффективнее писать и хочу понять, есть ли смысл ворошить былое или лучше сразу устремиться в дивный новый мир, который построил Хэдли.
для скорости — в data.table
Ну хорошо. А есть какая-нибудь ссылка на почитать про все опасности этого group_by и прелести ungroup?
Я немного понял жизнь, поэтому не особо спешу.
И, кстати, это неправильный тест. Время исполнения — всего 100 мс. Он ничего не показывает. Есть еще понятие накладных на старт. На гитхабе за такие тесты постоянно ругают.
Наверное, доки... А про ungroup читать не надо. Просто, если следующей функции не нужна группировка, пишешь ungroup, а потом уже эту самую функцию
Попробую запомнить. Но с какой-нибудь "страшной историей" про то, что стало с одним вашим знакомым, который однажды забыл это сделать, мне было бы проще это сделать.
отрезать хвост по частям?
Из всего базового семейства имеет смысл lapply. И для прода vapply. apply и sapply вредны. Даже цикл будет лучше, чем они
Я пока ни разу не столкнулся с ситуацией, когда скорость работы кода что-то для меня решала. Как только — так сразу.
да он этот хвост уже лет пять режет минимум, я уже ждать устал %)))
тест показывает, что lapply просто быстрее ... и я не претендую на всесторонний разбор вопроса
Я к сожалению, не могу конкретную историю рассказать, потому что не помню подробностей. Только про arrange помню. Просто что-то неожиданно считается по группам, хотя хотелось бы без группировки. Кстати, сейчас почитал хелп к arrange - здравый смысл возобладал и он группировку игнорирует
Для честности library(purrr) smpl <- rexp(1e5, 2) bench::mark( lapply(smpl, log), purrr::map(smpl, log), map(smpl, log), log(smpl), check = FALSE ) # A tibble: 4 x 13 expression min median `itr/sec` mem_alloc `gc/sec` n_itr n_gc <bch:expr> <bch:tm> <bch:tm> <dbl> <bch:byt> <dbl> <int> <dbl> 1 lapply(smpl, log) 45.1ms 77.39ms 11.3 781KB 8.04 7 5 2 purrr::map(smpl, log) 239.7ms 295.91ms 3.38 781KB 10.1 2 6 3 map(smpl, log) 224.4ms 225.39ms 3.87 781KB 10.3 3 8 4 log(smpl) 3.4ms 3.72ms 249. 781KB 3.99 125 2 Векторизация бьет всех начисто. Применение :: тоже жрет время. А в серьезном кейсе lapply проигрывает: https://rpubs.com/wch/200398
Как раз в этом кейсе по ссылке проявились весь блеск и нищета tidyverse - там лидер by_row из purrr, но в современном purrr его уже нет
векторизация конечно бьет, но при работе со списками она будет бесполезна и тут вполне нормально заходит lapply без purrr ... хотя я не заморачиваюсь и бывает нещадно мешаю одно с другим и не комплексую по этому поводу ))
И всю эту пуррровскую братию mapply из базы заруливает почти в два раза. Такой вот mapply: f_mapply <- function(df) { do.call(mapply, c(list, df, SIMPLIFY = FALSE)) }
Есть, см https://cran.r-project.org/web/packages/purrrlyr/
Я вот даже никогда не задумывался. Мало того, что сортировка в группах в 99% бессмысленна, так она ещё и на несколько порядков медленнее, чем первичная сортировка всего дата фрейма
а сам apply чем вреден? просто в purrr как раз таки нет его аналога, насколько я помню, с матрицами получается самое то
С матрицами может и нормально. За исключением того, что он в некоторых случаях транспонирует результат, на мой взгляд, неочевидным способом. Если матрица, на выходе функции одно число, то вреда от него не будет. Да, и по скорости он был не быстрее аналогичного цикла. Может, сейчас улучшили...
если всегда хватает векторизации, то лучше векторизация, чем lapply/{purrr}, но если не хватает, то оставшаяся альтернатива — это циклы for и, ну, уж лучше использовать все-таки lapply/{purrr}, мне кажется. {purrr} можно использовать в отрыве от tidyverse, кстати. Некоторые вещи там понятнее, чем в *apply(). Например, проще понять использование суффиксов к map_*(), чем разобраться с vapply()
мне как-то казалось, что и так обычные *apply() функции, как и {purrr} не быстрее циклов, а немного их медленнее, потому что являются над ними обертками еще на уровне R, нет?
Если циклы правильно написаны то так и есть, но по факту никто не пишет правильные циклы
Хороший вопрос. lapply точно не медленнее циклов. В современных версиях R уже, наверное, сравнимо
А что значит «правильный цикл» кроме того, чтобы заранее создать объект нужной длины и его результатами расчетов
Некое ощущение «правильности «можно составить при прочтении: http://r-statistics.co/Strategies-To-Improve-And-Speedup-R-Code.html#1.%20Vectorize%20and%20Pre-allocate
ну, там только первый пункт про правильное использование циклов (вот как раз про preallocation, про который я говорил(, а все остальное сводится к «не используйте циклы». При этом некоторые его варианты достаточно странные (если уж дататейбл, то зачем изменять дататейбл внутри цикла?), не говоря уже о том, что он не использует очень понятный (и, скорее всего, более быстрый, чем его варианты) способ векторизации: system.time({df$V5 <- "lesser_than_4" df$V5[(df$col1 + df$col2 + df$col3 + df$col4 > 4)] <- "greater_than_4" })
Добавлю к предыдущему оратору, что параллелить код просто так не подумав - так себе затея. Можно прочесть по памяти очень быстро и иногда параллельный код бывает медленнее однопоточного
ну еще объект не создавать внутри цикла, append() не использовать, использовать which(), держать if() с наружи цикла ... наверное еще что-то есть - я не знаю ... я циклы стараюсь не писать
ктоб спорил то ))) думать и тестировать код - это хорошо, маленькая пенсия - это плохо ))
Параллелить не понимая общих принципов и специфики задачи — неблагодарное дело. Чаще всего будет хуже.
Так я о том же. Я шишек в своë время набил)) тебе другим говорю, что и на одном потоке неплохо живëтся почти всегда))
Но это не повод не открывать новые возможности :)
Обсуждают сегодня