【问题标题】:Passing column name as parameter to a function using dplyr使用 dplyr 将列名作为参数传递给函数
【发布时间】:2018-05-09 17:59:40
【问题描述】:

我有一个如下的数据框:

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 包动词为每个 accountid 编写每月总金额的函数。

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

我收到如下错误:- sum(col3) 中的错误:参数的“类型”(字符)无效。如何在汇总函数中将列名作为参数传递而不带引号?

【问题讨论】:

    标签: r dataframe dplyr quosure


    【解决方案1】:

    我会建议以下解决方案:

    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)
    

    注意事项

    • 如果您查看Programming with 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, dots) 中的错误:无法修改列 am 因为它是一个分组变量

      如果您要使用mutate() 原始数据或执行其他操作以保持分组变量不变,则应使用ungroup()。传递分组变量以后可能会被证明是有问题的,它会说这主要是您dplyr 工作流程中的品味/顺序问题。如果您和其他函数用户要记住 tibble 可能带有分组变量,那么就没有问题;就个人而言,我倾向于忘记这一点,所以如果我对携带分组变量不感兴趣,我更喜欢ungroup() 数据。

    【讨论】:

      【解决方案2】:

      您可以使用 quo() 将 quosure 对象作为参数传递,然后使用某种 unquote 函数懒惰地评估它们,在本例中我使用 !!

      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))
      

      【讨论】:

        猜你喜欢
        • 2015-04-04
        • 2015-03-29
        • 2018-05-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-14
        相关资源
        最近更新 更多