【问题标题】:Using dplyr functions within another function在另一个函数中使用 dplyr 函数
【发布时间】:2015-10-04 09:12:02
【问题描述】:

我一直在努力解决这个与a question raised here before 非常相似的问题。不知何故,我无法将该问题中给出的解决方案转化为我自己的问题。

我首先制作一个示例数据框:

test.df <- data.frame(col1 = rep(c('a','b'), each=5), col2 = runif(10))
str(test.df)

以下函数应基于“groupvar”的组创建一个具有“statvar”平均值的新数据框。

test.f <- function(df, groupvar, statvar) {
  df %>% 
    group_by_(groupvar) %>% 
    select_(statvar) %>%
    summarise_(
      avg = ~mean(statvar, na.rm = TRUE)
    )
} 

test.f(df = test.df,
       groupvar = "col1",
       statvar = "col2")

我希望它返回的是一个具有 2 个计算平均值的数据框(一个用于 col1 中的所有 a 值,一个用于 col1 中的所有 b 值)。相反,我得到了这个:

  col1 avg
1    a  NA
2    b  NA
Warning messages:
1: In mean.default("col2", na.rm = TRUE) :
  argument is not numeric or logical: returning NA
2: In mean.default("col2", na.rm = TRUE) :
  argument is not numeric or logical: returning NA

我觉得这很奇怪,因为我很确定 col2 是数字:

str(test.df)
'data.frame':   10 obs. of  2 variables:
 $ col1: Factor w/ 2 levels "a","b": 1 1 1 1 1 2 2 2 2 2
 $ col2: num  0.4269 0.1928 0.7766 0.0865 0.1798 ...

【问题讨论】:

    标签: r dplyr


    【解决方案1】:
    library(lazyeval)
    library(dplyr)
    
    test.f <- function(df, groupvar, statvar) {
      test.df %>% 
        group_by_(groupvar) %>% 
        select_(statvar) %>%
        summarise_(
          avg = (~mean(statvar, na.rm = TRUE)) %>%
            interp(statvar = as.name(statvar))
        )
    } 
    
    test.f(df = test.df,
           groupvar = "col1",
           statvar = "col2")
    

    您的问题是“col2”被替换为 statvar,而 mean("col2") 未定义

    【讨论】:

    • 这很好用,非常感谢。所以 interp() 基本上说“R,你应该把它看作一个变量而不是一个字符串”?不过我还是有点疑惑,为什么 avg 用管道符号 %>% 连接到 interp()。
    • @1053Inator,你可以写成avg = interp(~mean(statvar, na.rm = TRUE), statvar = as.name(statvar)),不用管道
    • interp 采用表达式~mean(statvar, na.rm = TRUE) 并在每次看到单词 statvar 时将其替换为 as.name(statvar) 的结果,即 col2。所以表达式转换为~mean(col2, na.rm = TRUE)
    【解决方案2】:

    随着即将发布的 dplyr 0.6.0,新功能可以提供帮助。新函数是UQ(),它取消了引用的内容。您正在输入statvar 作为"col1" 之类的字符串。 dplyr 具有可以像group_by_select_ 一样定期评估的替代函数。但是对于summarise_,字符串的更改可能很难看,就像上面的答案一样。我们现在可以使用常规的summarise 函数并取消引用带引号的变量名。有关“取消引用引用”的更多帮助,see this vignette。现在the developer's version 拥有它。

    library(dplyr)
    test.df <- data.frame(col1 = rep(c('a','b'), each=5), col2 = runif(10))
    test.f <- function(df, groupvar, statvar) {
      q_statvar <- as.name(statvar)
      df %>% 
        group_by_(groupvar) %>% 
        select_(statvar) %>%
        summarise(
          avg = mean(!!q_statvar, na.rm = TRUE)
        )
    } 
    
    test.f(df = test.df,
           groupvar = "col1",
           statvar = "col2")
    # # A tibble: 2 × 2
    #     col1       avg
    #   <fctr>     <dbl>
    # 1      a 0.6473072
    # 2      b 0.4282954
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多