6

我正在尝试编写一个函数,该函数将数据框和函数名称作为参数。当我尝试使用标准 R 语法编写函数时,我可以使用@hadley 在http://adv-r.had.co.nz/Computing-on-the-language.htmleval中的建议获得良好的结果substitute

> df <- data.frame(y = 1:10)
> f <- function(data, x) {
+   out <- mean(eval(expr = substitute(x), envir = data))
+   return(out)
+ }
> f(data = df, x = y)
[1] 5.5

现在,当我尝试使用%>%运算符编写相同的函数时,它不起作用:

> df <- data.frame(y = 1:10)
> f <- function(data, x) {
+   data %>% 
+     eval(expr = substitute(x), envir = .) %>% 
+     mean()
+ }
> f(data = df, x = y)
Show Traceback
Rerun with Debug
 Error in eval(expr, envir, enclos) : objet 'y' introuvable 
> 

如何将管道运算符与evaland结合使用substitute?这对我来说似乎真的很棘手。

4

3 回答 3

7

一种解决方法是

f <- function(data, x) {
  v <- substitute(x)
  data %>% 
    eval(expr = v, envir = .) %>%
    mean()
}

问题是管道函数 ( %>%) 正在创建另一个级别的闭包,这会干扰substitute(x). 你可以看到这个例子的不同之处

df <- data.frame(y = 1:10)
f1 <- function(data, x) {
  print(environment())
  eval(expr = environment(), envir = data)
}

f2 <- function(data, x) {
  print(environment())
  data %>% 
    eval(expr = environment(), envir = .)
}
f1(data = df, x = y)
# <environment: 0x0000000006388638>
# <environment: 0x0000000006388638>
f2(data = df, x = y)
# <environment: 0x000000000638a4a8>
# <environment: 0x0000000005f91ae0>

请注意 matrittr 版本中的环境有何不同。substitute在处理非标准评估时,您想尽快处理事情。

我希望你的用例比你的例子复杂一点,因为它看起来像

mean(df$y)

将是更容易阅读的代码。

于 2016-02-11T17:35:56.347 回答
3

我一直在努力理解我的问题。

首先,我用summarise()函数写了我想要的:

> library(dplyr)
> df <- data.frame(y = 1:10)
> summarise_(.data = df, mean = ~mean(y))
  mean
1  5.5

然后我尝试编写自己的函数。我在这篇文章lazyeval中找到了一个似乎适用于该包的解决方案。我使用和函数来写我想要的。lazy()interp()

第一种可能性在这里:

> library(lazyeval)
> f <- function(data, col) {
+   col <- lazy(col)
+   inter <- interp(~mean(x), x = col)
+   summarise_(.data = data, mean = inter)    
+   }
> f(data = df, col = y)
  mean
1  5.5

我也可以使用管道:

> f <- function(data, col) {
+   col <- lazy(col)
+   inter <- interp(~mean(x), x = col)
+   data %>% 
+     summarise_(.data = ., mean = inter)    
+ }
> 
> f(data = df, col = y)
  mean
1  5.5
于 2016-02-18T16:10:19.013 回答
0

我不会使用 eval 和替代。

以下是适合您问题的这篇精彩帖子的简化版本。

df <- data.frame(y = 1:10)
f <- function(data, x) {
  x <- enquo(x)
  df %>% summarise(mean = mean(!!x))
   }
f(data = df, x = y)

这里发生了两件事:

  1. 使用转换列名enquo()
  2. 在列前加上!!

请参阅链接以获取更复杂的示例。

于 2021-05-06T13:29:06.167 回答