Передача имени столбца в качестве параметра функции с помощью dplyr

У меня есть датафрейм, как показано ниже:

transid<-c(1,2,3,4,5,6,7,8)
accountid<-c(a,a,b,a,b,b,a,b)
month<-c(1,1,1,2,2,3,3,3)
amount<-c(10,20,30,40,50,60,70,80)
transactions<-data.frame(transid,accountid,month,amount)

Я пытаюсь написать функцию для общей ежемесячной суммы для каждого счета, используя глаголы пакета dplyr.

my_sum<-function(df,col1,col2,col3){
df %>% group_by_(col1,col2) %>%summarise_(total_sum = sum(col3))
}

my_sum(transactions, "accountid","month","amount")

Чтобы получить результат, как показано ниже:

accountid   month  total_sum
a            1       30
a            2       40
a            3       70
b            1       30
b            2       50
b            3       140

Я получаю сообщение об ошибке типа:- Ошибка в сумме (col3): неверный тип (символ) аргумента. Как передать имя столбца в качестве параметра без кавычек в функции суммирования?

2 ответа

Я бы предложил следующее решение:

my_sum <- function(df, col_to_sum,...) {

    col_to_sum <- enquo(col_to_sum)
    group_by <- quos(...)

    df %>%
        group_by(!!!group_by) %>%
        summarise(total_sum = sum(!!col_to_sum)) %>% 
        ungroup()
}

transactions %>% my_sum(amount, accountid, month)

Результаты

>> transactions %>% my_sum(amount, accountid, month)
# A tibble: 6 x 3
  accountid month total_sum
     <fctr> <dbl>     <dbl>
1         a     1        30
2         a     2        40
3         a     3        70
4         b     1        30
5         b     2        50
6         b     3       140

Данные

В исходном ответе вы передали строки без кавычек, я решил, что используя Hmisc:Cs функции, но, в принципе, вы должны окружить свои струны ""; если, конечно, вы не вызываете некоторые объекты с именем a, b и так далее. Это не было ясно из исходного вопроса.

Используемые данные:

transid <- c(1, 2, 3, 4, 5, 6, 7, 8)
accountid <- Hmisc::Cs(a, a, b, a, b, b, a, b)
month <- c(1, 1, 1, 2, 2, 3, 3, 3)
amount <- c(10, 20, 30, 40, 50, 60, 70, 80)
transactions <- data.frame(transid, accountid, month, amount)

Заметки

  • Если вы посмотрите на раздел " Захват нескольких переменных" программирования с dplyr В статье вы увидите, что очень похожая проблема решается с использованием quos() функция. По сути, ваша задача является прекрасным примером того, как quos() Функция должна быть использована.

  • Многоточие ... Затем должен прийти в конце, так как предполагается, что функция будет использоваться для группировки данных с несколькими столбцами. Естественно, при желании вы можете передать столбцы один за другим enquo() каждый столбец и так далее, но с использованием ... является более естественным и совместимым с рекомендуемым решением, рассмотренным в статье, приведенной выше. Обратите внимание, что этот подход меняет порядок аргументов в вызове вашей функции как ... должен прийти в конце.

  • Если вы используете summarise() тебе не нужно ungroup() ваши данные как в моем примере. Например код:

    mtcars %>% group_by(am) %>% summarise(mean_disp = mean(disp)) %>% mutate(am = am + 1) 
    

    буду работать; тогда как код:

    mtcars %>% group_by(am)  %>% mutate(am = am + 1)
    

    вернет ожидаемую ошибку:

    Ошибка в mutate_impl(.data, точки): столбец am не может быть изменено, потому что это переменная группировки

    Вы должны использовать ungroup() если вы собираетесь mutate() ваши исходные данные или делать другие операции, которые сохраняют вашу переменную группировки нетронутой. Передача сгруппированной переменной может позже оказаться проблематичной, это скажет, что это в основном вопрос вкуса / порядка в вашем dplyr рабочий процесс. Если вы и другие пользователи функций будете помнить, что тиббл может содержать переменную группировки, тогда проблем нет; лично я склонен забывать об этом, поэтому я предпочитаю ungroup() данные, если я не заинтересован в переносе групповой переменной.

Вы можете передавать объекты quosure в качестве аргументов, используя quo() а затем оценивать их лениво, используя некую функцию кавычек, в этом примере я использую !!

library(tidyverse)
my_sum<-function(df,col1,col2,col3){
df %>% group_by(!!col1,!!col2) %>%summarise(total_sum = sum(!!col3))
}

my_sum(transactions, quo(accountid),quo(month),quo(amount))
Другие вопросы по тегам