以编程方式在可变变量上调用 group_by()
Programmatically calling group_by() on a varying variable
使用 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
我会 post 一个解决方案,但很想知道其他人是如何解决这个问题的。
这是一种解决方案以及我是如何找到它的。
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 ) )
dplyr 的下划线函数可能对此有用:
ChickWeight %>% group_by_( "Chick", v ) %>% summarise( mw = mean( weight ) )
您现在可以使用 dplyr 进行编程——每个使用非标准评估 (NSE) 的函数也有一个以 _
结尾的标准评估 (SE) 孪生。例如,filter() 的 SE 版本称为 filter_
()。每个函数的 SE 版本都有相似的参数,但它们必须明确地“引用”。
使用 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
我会 post 一个解决方案,但很想知道其他人是如何解决这个问题的。
这是一种解决方案以及我是如何找到它的。
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 ) )
dplyr 的下划线函数可能对此有用:
ChickWeight %>% group_by_( "Chick", v ) %>% summarise( mw = mean( weight ) )
您现在可以使用 dplyr 进行编程——每个使用非标准评估 (NSE) 的函数也有一个以 _
结尾的标准评估 (SE) 孪生。例如,filter() 的 SE 版本称为 filter_
()。每个函数的 SE 版本都有相似的参数,但它们必须明确地“引用”。