Функция dplyr с необязательной группировкой только при наличии аргумента - PullRequest
0 голосов
/ 16 октября 2018

Мне нужно написать функцию dplyr, которая создает настраиваемый участок площади.Итак, вот моя попытка.

area_plot <- function(data, what, by){
  by <- ensym(by)
  what <- ensym(what)

  data %>% 
    filter(!is.na(!!by)) %>% 
    group_by(date, !!by) %>% 
    summarise(!!what := sum(!!what, na.rm = TRUE)) %>% 
    complete(date, !!by, fill = rlang::list2(!!what := 0)) %>% 
    ggplot(aes(date, !!what, fill = !!by)) +
    geom_area(position = 'stack') +
    scale_x_date(breaks = '1 month', date_labels = '%Y-%m', expand = c(.01, .01)) +
    theme_minimal() +
    theme(axis.text.x = element_text(angle = 90, vjust = .4)) +
    labs(fill = '')
}

Но мне было интересно, есть ли какое-либо значение по умолчанию для аргумента by, которое выводило бы geom_area plot для всех групп вместе.Я знаю, что могу использовать if, чтобы сначала определить данные, используемые в ggplot2, и сделать что-то подобное внутри функции:

if (by != 'default') {
    data <- data %>% 
    filter(!is.na(!!by)) %>% 
    group_by(date, !!by) %>% 
    summarise(!!what := sum(!!what, na.rm = TRUE)) %>% 
    complete(date, !!by, fill = rlang::list2(!!what := 0))}

ggplot(data, aes(date, !!what, fill = !!by)) +
geom_area(position = 'stack') +
scale_x_date(breaks = '1 month', date_labels = '%Y-%m', expand = c(.01, .01)) +
theme_minimal() +
theme(axis.text.x = element_text(angle = 90, vjust = .4)) +
labs(fill = '')

Но я размышляю, есть ли хитрый трюк для предоставления некоторого значения (например,константа) до group_by, что позволило бы summarise сохранить исходную структуру (поэтому в основном ничего не делать) несмотря на вызов.Поведение аналогично тому, когда вы вводите константу для некоторой эстетики в ggplot2.

Пожалуйста, см. Образец прилагаемых данных.group является необязательной переменной группировки.

structure(list(date = structure(c(17052, 17654, 17111, 17402, 
17090, 17765, 17181, 17301, 17496, 17051, 16980, 17155, 17599, 
16986, 17607, 17620, 17328, 17085, 17666, 17759, 17238, 16975, 
17242, 17322, 17625, 17598, 17124, 17648, 17675, 17613, 17044, 
16984, 16968, 17421, 17152, 17148, 17418, 17017, 17655, 17148, 
16981, 17644, 17149, 17090, 17548, 17474, 17564, 17530, 17237, 
17679, 17166, 17470, 17427, 17306, 17677, 17600, 17458, 17697, 
17602, 16990, 17111, 17150, 17561, 17406, 17135, 17181, 17014, 
17419, 17273, 17416, 17101, 17367, 17170, 17015, 17386, 17444, 
17507, 17592, 17058, 17292, 16966, 17756, 17239, 17479, 17260, 
17477, 16989, 17032, 17219, 17430, 17696, 17487, 17578, 17759, 
17269, 17634, 17279, 17478, 17222, 17296), class = "Date"), count = c(2, 
4, 2, 3, 6, 1, 4, 8, 1, 5, 1, 5, 1, 1, 2, 6, 3, 5, 2, 7, 3, 4, 
1, 3, 4, 2, 4, 1, 2, 3, 16, 1, 5, 4, 3, 4, 4, 6, 1, 3, 3, 1, 
3, 10, 5, 1, 4, 2, 2, 4, 5, 26, 4, 9, 3, 1, 3, 1, 4, 1, 2, 3, 
1, 13, 3, 1, 3, 1, 1, 3, 1, 3, 3, 4, 1, 2, 2, 3, 1, 9, 3, 1, 
2, 1, 4, 2, 1, 2, 4, 3, 2, 3, 1, 6, 5, 1, 2, 2, 3, 4), group = c("NON-FOOD", 
NA, NA, NA, NA, "MIX", NA, NA, "MIX", NA, NA, NA, NA, NA, NA, 
NA, NA, NA, NA, NA, NA, NA, NA, "FOOD", NA, "FOOD", NA, NA, "MIX", 
NA, NA, NA, "FOOD", "FOOD", NA, NA, NA, NA, "FOOD", NA, NA, "FOOD", 
NA, NA, NA, "FOOD", NA, NA, NA, NA, NA, NA, NA, NA, "MIX", NA, 
NA, "FOOD", NA, "FOOD", NA, NA, "FOOD", NA, "FOOD", NA, NA, "NON-FOOD", 
NA, NA, "MIX", "NON-FOOD", NA, NA, NA, NA, NA, NA, "IMAGE", NA, 
"FOOD", NA, NA, NA, "FOOD", NA, "FOOD", NA, NA, NA, NA, NA, NA, 
NA, NA, "FOOD", "FOOD", NA, NA, NA)), row.names = c(73008L, 535553L, 
122359L, 321655L, 105632L, 646925L, 172409L, 256204L, 394666L, 
72385L, 20180L, 156162L, 478525L, 91409L, 485397L, 501386L, 277336L, 
100902L, 549629L, 640676L, 209400L, 16603L, 224543L, 272638L, 
505291L, 475497L, 131845L, 529041L, 558295L, 491746L, 67156L, 
23499L, 11150L, 334454L, 154958L, 150674L, 333348L, 45599L, 536064L, 
150673L, 20668L, 524095L, 151809L, 105713L, 433853L, 375687L, 
445626L, 420587L, 208594L, 562514L, 162403L, 372594L, 338509L, 
259784L, 560356L, 480072L, 361471L, 579474L, 481262L, 26469L, 
122119L, 152537L, 443426L, 325045L, 140531L, 171908L, 43547L, 
333968L, 237152L, 332106L, 114754L, 298081L, 164923L, 43577L, 
311250L, 350267L, 404348L, 470188L, 78329L, 250086L, 9486L, 638289L, 
209638L, 379370L, 227299L, 377487L, 26333L, 55058L, 195261L, 
340666L, 578515L, 387600L, 457752L, 640729L, 235389L, 514348L, 
240303L, 378836L, 197409L, 252746L), class = "data.frame")

1 Ответ

0 голосов
/ 16 октября 2018

Вот один из способов сделать первые несколько шагов вашей функции (я не стал вдаваться во все вещи ggplot, просто как вы могли бы подходить к группировке).В общем, чтобы установить действие по умолчанию «ничего не делать», например, по умолчанию не группировать, вы будете использовать argument = NULL в своей функции - вы можете просмотреть страницы документации других функций, чтобы увидеть, как это делается. Вот SO сообщение о разнице между NA и NULL.

Я не супер адепт по работе с квазерами, но я построил несколько функций и часто полагаюсьна некоторых rlang / tidyselect вспомогательных функциях, таких как rlang::quo_is_null, которые я здесь использую.Кто-то другой может переписать это без помощников.

Сначала вы увидите поведение, которое вы ищете, в виде сгруппированных или не сгруппированных резюме:

library(tidyverse)

# grouped
df %>%
  filter(!is.na(group)) %>%
  group_by(group) %>%
  summarise(count = sum(count, na.rm = TRUE))
#> # A tibble: 4 x 2
#>   group    count
#>   <chr>    <dbl>
#> 1 FOOD        34
#> 2 IMAGE        1
#> 3 MIX          8
#> 4 NON-FOOD     6

# not grouped
df %>%
  # add in if you want to filter ungrouped data
  summarise(count = sum(count, na.rm = TRUE))
#>   count
#> 1   347

Затем в функции,Я создаю what_var в качестве версии для проверки what (эксперты Rlang, не стесняйтесь поправлять меня в этой терминологии ...?).Я обычно добавляю _var к именам, чтобы отследить, что является исходным аргументом и что уже было enquo ed.Проверьте, является ли аргумент by нулевым, создав выражение by и проверив, является ли он нулевым.Если оно не равно нулю, то есть если для by было указано имя столбца, отфильтруйте и сгруппируйте по этому предложению.Если он нулевой, просто передайте исходный фрейм данных.Я передаю данные новой переменной в операторе else, чтобы избежать работы с исходным фреймом данных.Затем, независимо от того, сгруппированы ли данные, суммируйте what.

to_group_or_not_to_group <- function(data, what, by = NULL) {
  what_var <- enquo(what)

  if(!rlang::quo_is_null(enquo(by))) {
    by_var <- enquo(by)

    grouped_or_not <- data %>%
      filter(!is.na(!!by_var)) %>%
      group_by(!!by_var)
  } else {
    grouped_or_not <- data
  }

  grouped_or_not %>%
    summarise(!!quo_name(what_var) := sum(!!what_var, na.rm = TRUE))

}

Убедитесь, что вы получили намеченные результаты.С переменной группировки:

df %>%
  to_group_or_not_to_group(what = count, by = group)
#> # A tibble: 4 x 2
#>   group    count
#>   <chr>    <dbl>
#> 1 FOOD        34
#> 2 IMAGE        1
#> 3 MIX          8
#> 4 NON-FOOD     6

Предоставление NULL в качестве (отсутствия) переменной группировки:

df %>%
  to_group_or_not_to_group(what = count, by = NULL)
#>   count
#> 1   347

Без переменной группировки, откат к значению по умолчанию by = NULL:

df %>%
  to_group_or_not_to_group(what = count)
#>   count
#> 1   347

Создано в 2018-10-16 гг. представительным пакетом (v0.2.1)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...