r-将函数传递给封装在函数内部的ddply,作为该函数调用的一部分



我希望在函数中使用ddply,通过传递汇总函数的名称作为函数调用中的变量应用,根据用户确定的汇总统计数据(例如平均值、中值、最小值、最大值)来汇总组。然而,我不知道如何将此传递给ddply。

简单,例如

library(plyr)
test.df<-data.frame(group=c("a","a","b","b"),value=c(1,5,5,15))
ddply(test.df,.(group),summarise, mean=mean(value, na.rm=TRUE))

我该如何设置如下内容,并将相关函数传递给ddply(当然还有一个函数,尽管一旦解决了第一个问题,这应该很简单)。注意每个汇总度量(平均值等)都需要na.rm=TRUE。我可以通过为每个汇总统计编写自己的替换函数来实现这一点,但这似乎过于复杂。

所需:

#fn<-"mean"     
#ddply(test.df,.(group),summarise, fn=fn(value, na.rm=TRUE))

感谢人们提供的任何帮助。

编辑!感谢大家的回复。我最初认为去掉引号是可行的,但这种方法,也不使用getFunction或match.fun,只要fn作为函数调用的一部分是特定的。我真正希望的是按照下面的代码进行操作(返回一个错误)。很抱歉没有在第一时间提供一个更彻底的例子。。。

test.df<-data.frame(group=c("a","a","b","b"),value=c(1,5,5,15))
my.fun <- function(df, fn="mean") {
summary <- ddply(df,.(group),summarise, summary=match.fun(fn)(value, na.rm=T))
return(summary)
}
my.fun(test.df, fn="mean")

您在问题中提供的函数看起来应该可以工作。(事实上,我花了一些时间才想起为什么它不会)。它又来了,为了清晰起见,稍微重写了一下(我很乐意在没有任何空格的情况下回答你的问题;)

df <- data.frame(
group = c("a", "a" ,"b" ,"b" ), 
value = c(1, 5, 5, 15)
)
my_fun <- function(df, fn = "mean") {
fn <- match.fun(fn)
ddply(df, .(group), summarise, summary = fn(value, na.rm = TRUE))
}

它不起作用的原因有点微妙,但归根结底是作用域(从变量名称中查找变量值的过程)是如何起作用的。summarise()使用非标准求值来查找数据帧中的值,以及从中调用它的环境。这对value有效,但对fn无效,因为它不存在于调用summarise()的地方,即在ddply()中。

有两种解决方案:

  1. 使用添加到plyr的here()函数来解决问题这个问题

    my_fun <- function(df, fn = "mean") {
    fn <- match.fun(fn)
    ddply(df, .(group), here(summarise), summary = fn(value, na.rm = TRUE))
    }
    my_fun(df, "mean")
    
  2. 稍微不那么简洁,使用显式函数:

    my_fun <- function(df, fn = "mean") {
    fn <- match.fun(fn)
    ddply(df, .(group), function(df) {
    summarise(df, summary = fn(value, na.rm = TRUE))
    })
    }
    my_fun(df, "mean")
    

我现在明白了在plyer的设计中如何首先避免这个问题,但它需要一些自定义的C/C++代码。它在dplyr中已修复,但不太可能移植回plyr,因为它可能会破坏现有代码。

您可以使用getFunction:

fn<-"mean"     
ddply(test.df,.(group),summarise, fn=getFunction(fn)(value, na.rm=TRUE))
#  group fn
#1     a  3
#2     b 10

然而,如果您将其放入包装器函数中,您可能会迷失在环境的丛林中。

它与match.fun:一起工作

fn <- "mean"
ddply(test.df, .(group), summarise, fn = match.fun(fn) (value, na.rm = TRUE))
#  group fn
# 1     a  3
# 2     b 10

最新更新