我有一个如下数据框:
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
我收到如下错误: - 总和错误(col3):无效&#39;输入&#39;参数的(字符)。如何在汇总函数中将列名作为参数传递而不引用?
答案 0 :(得分:3)
我建议采用以下解决方案:
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
在你原来的回答中你已经通过了unqoted字符串,我已经使用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
无法修改 因为它是一个分组变量
如果您要ungroup()
原始数据或执行其他操作以保持分组变量不变,则应使用mutate()
。传递分组变量可能后来证明有问题,它会说它主要是dplyr
工作流程中的品味/顺序问题。如果你和其他功能用户要记住tibble可能携带分组变量那么就没有问题;就个人而言,我倾向于忘记这一点,所以如果我对携带分组变量不感兴趣,我倾向于ungroup()
数据。
答案 1 :(得分:0)
您可以使用quo()
将quosure对象作为参数传递,然后使用某种非引号函数懒惰地评估它们,在本例中我使用!!
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))