Замените несколько `суммировать` заявления функцией - PullRequest
4 голосов
/ 29 апреля 2019

Я сейчас повторяю много кода, так как мне нужно summarize всегда одни и те же столбцы для разных групп.Как я могу сделать это эффективно, написав функцию summarize (которая всегда одинакова) только один раз, но определяя имя выхода и group_by аргументы для каждого конкретного случая?

Минимальный пример:

col1 <- c("UK", "US", "UK", "US")
col2 <- c("Tech", "Social", "Social", "Tech")
col3 <- c("0-5years", "6-10years", "0-5years", "0-5years")
col4 <- 1:4
col5 <- 5:8

df <- data.frame(col1, col2, col3, col4, col5)

result1 <- df %>% 
  group_by(col1, col2) %>% 
  summarize(sum1 = sum(col4, col5))

result2 <- df %>% 
  group_by(col2, col3) %>% 
  summarize(sum1 = sum(col4, col5))

result3 <- df %>% 
  group_by(col1, col3) %>% 
  summarize(sum1 = sum(col4, col5))

Ответы [ 4 ]

5 голосов
/ 29 апреля 2019

Использование combn :

combn(colnames(df)[1:3], 2, FUN = function(x){
  df %>% 
    group_by(.dots = x) %>% 
    summarize(sum1 = sum(col4, col5))
  }, simplify = FALSE)
2 голосов
/ 29 апреля 2019

Чтобы использовать dplyr в собственных функциях, вы можете использовать аккуратную оценку. Причиной этого является то, что dplyr оценивает код dplyr, что называется нестандартной оценкой, которая оборачивает все, что не ведет себя как обычный код R. Я рекомендую прочитать это:

https://tidyeval.tidyverse.org/modifying-inputs.html#modifying-quoted-expressions

summarizefunction <- function(data, ..., sumvar1, sumvar2) {

    groups <- enquos(...)
    sumvar1 <- enquo(sumvar1)
    sumvar2 <- enquo(sumvar2)

    result <- data %>%
        group_by(!!!groups) %>%
        summarise(sum1 = sum(!!sumvar1, !!sumvar2))
    return(result)
}

summarizefunction(df, col1, col2, sumvar1 = col4, sumvar2 = col5)

Вы можете использовать ключевое слово enquo для переноса параметров кавычек, что предотвращает их немедленную оценку. Для этого вы можете использовать оператор !! (так называемый взрыв). Я думаю, что это наиболее гибкое и многократно используемое решение, даже если вам нужно написать еще немного исходного кода.

1 голос
/ 02 мая 2019

Вы также можете использовать purrr::partial в следующих ситуациях:

library(purrr)
summarize45 <- partial(summarize, sum1 = sum(col4, col5))

result1b <- df %>% 
  group_by(col1, col2) %>%
  summarize45()

identical(result1, result1b)
# [1] TRUE

Или толкать дальше:

gb_df <- partial(group_by, df)

result1c <- gb_df(col1, col2) %>% summarize45()

identical(result1, result1c)
# [1] TRUE
1 голос
/ 29 апреля 2019

Во-первых, вам нужно оценить переменные с помощью такой функции:

library(tidyverse)
res_func <- function(x, y){
  df %>% 
  group_by(!!as.symbol(x), !!as.symbol(y)) %>% 
  summarize(sum1 = sum(col4, col5))
}

работает заклинание:

res_func("col1", "col2")

# A tibble: 4 x 3
# Groups:   col1 [2]
  col1  col2    sum1
  <fct> <fct>  <int>
1 UK    Social    10
2 UK    Tech       6
3 US    Social     8
4 US    Tech      12

Мы можем использовать assign, чтобы создать функцию, которая присваивает вашему кадру имена с параметрами, которые вы передали через функцию:

res_func2 <- function(x, y){
  assign(paste0("result_", x, y),
         df %>% 
           group_by(!!as.symbol(x), !!as.symbol(y)) %>% 
           summarize(sum1 = sum(col4, col5)), 
         envir = parent.frame())
}

Это создает новый df с именем result_col1col2, просто запустив res_func2("col1", "col2")

> result_col1col2
# A tibble: 4 x 3
# Groups:   col1 [2]
  col1  col2    sum1
  <fct> <fct>  <int>
1 UK    Social    10
2 UK    Tech       6
3 US    Social     8
4 US    Tech      12
...