使用 dplyr 将列名作为参数传递给函数

vsb*_*vsb 3 r dataframe dplyr quosure

我有一个如下所示的数据框:

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)
Run Code Online (Sandbox Code Playgroud)

我正在尝试使用 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")
Run Code Online (Sandbox Code Playgroud)

得到如下结果:

accountid   month  total_sum
a            1       30
a            2       40
a            3       70
b            1       30
b            2       50
b            3       140
Run Code Online (Sandbox Code Playgroud)

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

Kon*_*rad 5

我会建议以下解决方案:

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)
Run Code Online (Sandbox Code Playgroud)

结果

>> 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
Run Code Online (Sandbox Code Playgroud)

数据

在您的原始答案中,您已经传递了未定义的字符串,我已经使用Hmisc:Cs函数解决了该问题,但是原则上,您应该用"";包围您的字符串。当然,除非您正在调用一些名为 的对象ab等等。从最初的问题中并不清楚。

使用数据:

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)
Run Code Online (Sandbox Code Playgroud)

笔记

  • 如果您查看使用文章编程捕获多个变量部分,您会发现使用函数解决了非常相似的问题。实际上,您的任务是如何使用该函数的完美示例。dplyrquos()quos()

  • 省略号...应该放在最后,因为假设该函数将用于对具有多列的数据进行分组。自然地,如果需要,您可以enquo()每列逐一传递列,依此类推,但使用...更自然,并且与上面链接的文章中讨论的推荐解决方案一致。请注意,这种方法会更改函数调用中参数的顺序,这...应该在最后。

  • 如果您正在使用summarise()则不必 ungroup()像我的示例中那样使用数据。例如代码:

    mtcars %>% group_by(am) %>% summarise(mean_disp = mean(disp)) %>% mutate(am = am + 1) 
    
    Run Code Online (Sandbox Code Playgroud)

    将工作; 而代码:

    mtcars %>% group_by(am)  %>% mutate(am = am + 1)
    
    Run Code Online (Sandbox Code Playgroud)

    将返回预期的错误:

    mutate_impl(.data, dots) 中的错误:am无法修改列,因为它是分组变量

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