在函数中使用dplyr,非标准评估

5

我试图理解dplyr使用的非标准评估,但没有成功。我想要一个简短的函数,返回指定变量的汇总统计信息(N、均值、标准差、中位数、四分位距、最小值、最大值)。

我的函数的简化版本...

my_summarise <- function(df = temp,
                         to.sum = 'eg1',
                         ...){
    ## Summarise
    results <- summarise_(df,
                          n = ~n(),
                          mean = mean(~to.sum, na.rm = TRUE))
    return(results)
}

并使用一些虚拟数据运行它...

set.seed(43290)
temp <- cbind(rnorm(n = 100, mean = 2, sd = 4),
              rnorm(n = 100, mean = 3, sd = 6)) %>% as.data.frame()
names(temp) <- c('eg1', 'eg2')
mean(temp$eg1)
  [1] 1.881721
mean(temp$eg2)
  [1] 3.575819
my_summarise(df = temp, to.sum = 'eg1')
    n mean
1 100   NA

N已经计算,但平均值没有计算出来,不知道为什么。

最终我希望我的函数更加通用,类似于...

my_summarise <- function(df = temp,
                         group.by = 'group'
                         to.sum = c('eg1', 'eg2'),
                         ...){
    results <- list()
    ## Select columns
    df <- dplyr::select_(df, .dots = c(group.by, to.sum))
    ## Summarise overall
    results$all <- summarise_each(df,
                                  funs(n = ~n(),
                                       mean = mean(~to.sum, na.rm = TRUE)))
    ## Summarise by specified group
    results$by.group <- group_by_(df, ~to.group) %>%
                        summarise_each(df,
                                       funs(n = ~n(),
                                       mean = mean(~to.sum, na.rm = TRUE)))        
    return(results)
}

在我转向更复杂的版本之前(我使用this example作为指导),我需要先让简单版本中的评估工作,因为那是绊脚石,对dplyr::select()的调用运行良好。

感谢您提供任何有关我做错了哪些方面的建议。

提前致谢


1个回答

7
基本思路是你必须自己构建适当的调用,最简单的方法是使用lazyeval包来完成。
在这种情况下,您希望以编程方式创建一个类似于~mean(eg1, na.rm = TRUE)的调用。如下所示:
my_summarise <- function(df = temp,
                         to.sum = 'eg1',
                         ...){
  ## Summarise
  results <- summarise_(df,
                        n = ~n(),
                        mean = lazyeval::interp(~mean(x, na.rm = TRUE),
                                                x = as.name(to.sum)))
  return(results)
}

当我在努力使事情工作时,我通常采取以下步骤:

  1. 记住,就像你已经拥有的~n()一样,调用也必须以~开头。
  2. 使用实际变量编写正确的调用,并查看它是否起作用(~mean(eg1, na.rm = TRUE))。
  3. 使用lazyeval::interp重新创建该调用,并通过仅运行interp来检查此操作以直观地了解其执行情况。

在这种情况下,我可能经常会写interp(~mean(x, na.rm = TRUE), x = to.sum)。但运行它将给我们~mean("eg1", na.rm = TRUE),这将把eg1视为字符而不是变量名。因此,我们使用as.name,如vignette("nse")所教授的那样。


3
谢谢,我曾经(盲目地)尝试使用波浪符号开始调用 mean(),但没有意识到需要使用 lazyeval::interp()。现在是再次阅读文档的时候了。干杯! - slackline

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