以编程方式调用 group_by() 以处理不同的变量

7
使用dplyr,我想按一个可变的变量进行汇总(例如在循环或应用程序风格命令中)。直接输入名称可以正常工作:
library(dplyr)
ChickWeight %>% group_by( Chick, Diet ) %>% summarise( mw = mean( weight ) )

但是group_by函数不支持字符向量,这使得传递结果更加困难。

v <- "Diet"
ChickWeight %>% group_by( c( "Chick", v ) ) %>% summarise( mw = mean( weight ) )
## Error

我会提供一种解决方案,但很好奇其他人是如何解决的。


1
总结+1 - Tyler Rinker
4
请改用 group_by_( c( "Chick", v ) ) 代替 group_by( c( "Chick", v ) ) - David Arenburg
1
当然,如果使用dplyr不可行,您也可以轻松地使用data.table完成 :) ,例如 library(data.table) ; as.data.table(ChickWeight)[, .(mw = mean(weight)), c("Chick", v)] - David Arenburg
2
@KonradRudolph - 我也使用summarise,主要是因为没有summarize_each。这样我就少了一件要记住的事情。 - Rich Scriven
1
@Richard 在 Hadley 的库中使用英式英语是一个不幸的(=糟糕的)决定。API 应该是统一的,而不是个性化的。我喜欢在我的所有写作中使用英国拼写,但我在我的代码中遵循统一、已经建立的美国拼写。当其他代码违反这个规则时,它非常令人恼火并且违反了 API 设计的各种原则(非英语编程语言通常被视为失败的实验有其原因)。因此,我强烈建议遵循美国拼写(而缺少 summarize_each 可能是一个疏忽)。 - Konrad Rudolph
显示剩余4条评论
2个回答

11

dplyr 的下划线函数可能对此很有用:

ChickWeight %>% group_by_( "Chick", v )  %>% summarise( mw = mean( weight ) )

来自于dplyr 0.3的新功能:

您现在可以使用dplyr进行编程 - 所有使用非标准评估(NSE)的函数还都有一个以_结尾的标准评估(SE)版本的双胞胎。例如,filter()的SE版本称为filter_()。每个函数的SE版本具有类似的参数,但它们必须明确地“引用”。


0

这里是一个解决方案以及我是如何得出它的。

group_by 期望什么?

> group_by
function (x, ..., add = FALSE) 
{
    new_groups <- named_dots(...)

进入兔子洞:

> dplyr:::named_dots
function (...) 
{
    auto_name(dots(...))
}
<environment: namespace:dplyr>
> dplyr:::auto_name
function (x) 
{
    names(x) <- auto_names(x)
    x
}
<environment: namespace:dplyr>
> dplyr:::auto_names
function (x) 
{
    nms <- names2(x)
    missing <- nms == ""
    if (all(!missing)) 
        return(nms)
    deparse2 <- function(x) paste(deparse(x, 500L), collapse = "")
    defaults <- vapply(x[missing], deparse2, character(1), USE.NAMES = FALSE)
    nms[missing] <- defaults
    nms
}
<environment: namespace:dplyr>
> dplyr:::names2
function (x) 
{
    names(x) %||% rep("", length(x))
}

利用这些信息,如何着手制定解决方案?

# Naive solution fails:
ChickWeight %>% do.call( group_by, list( Chick, Diet ) ) %>% summarise( mw = mean( weight ) )

# Slightly cleverer:
do.call( group_by, list( x = ChickWeight, Chick, Diet, add = FALSE ) ) %>% summarise( mw = mean( weight ) )
## But still fails with,
## Error in do.call(group_by, list(x = ChickWeight, Chick, Diet, add = FALSE)) : object 'Chick' not found

解决方案在于引用参数,以便推迟它们的评估,直到它们处于包含 x tbl 的环境中:

do.call( group_by, list( x = ChickWeight, quote(Chick), quote(Diet), add = FALSE ) ) %>% summarise( mw = mean( weight ) )
## Bingo!
v <- "Diet"
do.call( group_by, list( x = ChickWeight, quote(Chick), substitute( a, list( a = v ) ), add = FALSE ) ) %>% summarise( mw = mean( weight ) )

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接