ОсновнаяРецепты

Функция, которая вызывает dplyr

Ого, почти полтора года ничего не писал.
А причины в следующем: на rMoscow#2 я узнал о существовании сообщества ODS.AI. И все эти полтора года я зависал в их уютном slack-чатике. Соответственно, как и у почти каждого попавшего туда — у меня развился сильнейший комплекс неполноценности, после которого я уже и не знал — заниматься ли дальше этим делом… Нда.

Ну ладно — все равно надо вести какие-то рабочие заметки, дневники. Причем неплохо бы их продолжать делать на GitHub, но пока вроде короткие можно и тут. Я ж для себя в основном пока их веду.

Решил я тут все свое Shiny-наследие привести в нормальный вид. Провести рефакторинг моих прототипов, которые неожиданно прижились, и которые очень сложно стало поддерживать и развивать в production-режиме.
Рефакторинг буду делать в направлении Shiny Modules.
Получу библиотеку наиболее типичных use cases, с визуальной частью, серверной, и даже обсерверами.

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

USE_CASE.
Есть развернутый датафрейм. Ну, например по продажам. Регион, филиал, клиент, сумма. Все типичное.
Задача — вывести таблицу с агрегированными данными по региону.
В прототипе, где серверная часть одним куском — агрегирование делал вообще с помощью пакета sqldf — так как на тот момент мне было проще (В R я пришел из bi с помощью SQL).
Но когда стал пытаться сделать это в модуле, который вызывает функцию, в которой и должно было проводиться аггрегирование данных, то ничего особо уже не получилось. Хотелось сделать универсальную функцию, которой на вход подается dataframe, поля группировки, поля суммирования, а на выходе из нее возвращается также dataframe, уже обработанный. В общем, как сконструировать запрос sqldf к dataframe, который получен в функции как параметр — я так и не понял. Тогда решил, что у меня получится написать эту функцию как вызов dplyr. Не тут-то было 🙂 В dplyr поля в group_by передаются не как вектор строковых переменных с названием поля, а как сами переменные. А я хотел сделать универсальную функцию, и поэтому мне это не подходило.
Гугление приводило лишь к рецептам вроде использовать класс функций dplyr вроде group_by_ (с подчеркиванием). Но и тут в готовых рецептах не было примера как просуммировать несколько полей (например, рубли и штуки. По региону, ага).
Но все-таки каким-то чудом меня замкнуло, и я стал искать не как решить мою задачу с помощью Dplyr, а как выполнить строковую переменную как команду R. А сконструировать нужную строку-то я как-нибудь смогу. И да, нашелся такой способ — eval. Я подозревал что это и есть то, что надо, но самостоятельно заставить ее работать не смог. И лишь Гугл подсказал тонкости вызова. Надо вот так:
eval(parse(text="ВАША ТЕКСТОВАЯ СТРОКА С КОМАНДАМИ"))

Соответственно вот такая у меня получилась функция:

fun_agg_df <- function(in_df, group_column, sum_column, order_column) { s <-paste0( "in_df %>%
group_by(",paste(group_column,collapse = ','),") %>%
summarise(",paste(paste0('sum(',sum_column,')'),collapse = ','),") %>%
arrange(",paste(order_column,collapse = ','),") %>%
magrittr::set_colnames(c(group_column,sum_column))
")
out_df <- eval(parse(text=s)) return(out_df) }

И соответственно вот так она вызывается:
fun_agg_df(
warpbreaks,
group_column = c('wool', 'tension'),
sum_column = c('breaks'),
order_column = c('tension'))

PS. Посоветуйте уже нормальный плагин для WordPress, чтобы весь код вставлялся с форматированием, отступами, табуляциями. Сил моих уже нет...

Добавить комментарий

Этот сайт использует Akismet для борьбы со спамом. Узнайте как обрабатываются ваши данные комментариев.