【问题标题】:dplyr - using column names as function argumentsdplyr - 使用列名作为函数参数
【发布时间】:2021-06-24 04:35:27
【问题描述】:

使用数据框,我正在使用 dplyr 来聚合如下所示的某些列。

> data <- data.frame(a=rep(1:2,3), b=c(6:11))
> data
  a  b
1 1  6
2 2  7
3 1  8
4 2  9
5 1 10
6 2 11
> data %>% group_by(a) %>% summarize(tot=sum(b))
# A tibble: 2 x 2
      a   tot
  <int> <int>
1     1    24
2     2    27

这是完美的。但是我想为此创建一个可重用的函数,以便可以将列名作为参数传递。

查看here等相关问题的答案,我尝试了以下方法。

sumByColumn <- function(df, colName) {
  df %>%
  group_by(a) %>%
  summarize(tot=sum(colName))
  df
}

但是我无法让它工作。

> sumByColumn(data, "b")

 Error in summarise_impl(.data, dots) : 
  Evaluation error: invalid 'type' (character) of argument. 

> sumByColumn(data, b)

 Error in summarise_impl(.data, dots) : 
  Evaluation error: object 'b' not found. 
> 

【问题讨论】:

标签: r dplyr


【解决方案1】:

我们可以使用.data 代词。

library(dplyr)

sumByColumn <- function(df, colName) {
  df %>%
    group_by(a) %>%
    summarise(tot = sum(.data[[colName]]))
}

sumByColumn(data, "b")

#      a   tot
#* <int> <int>
#1     1    24
#2     2    27

【讨论】:

    【解决方案2】:

    这可以使用最新的dplyr 语法(可以在github 上看到):

    library(dplyr)
    library(rlang)
    sumByColumn <- function(df, colName) {
      df %>%
        group_by(a) %>%
        summarize(tot = sum(!! sym(colName)))
    }
    
    sumByColumn(data, "b")
    ## A tibble: 2 x 2
    #      a   tot
    #  <int> <int>
    #1     1    24
    #2     2    27
    

    另一种将b 指定为变量的方法:

    library(dplyr)
    sumByColumn <- function(df, colName) {
      myenc <- enquo(colName)
      df %>%
        group_by(a) %>%
        summarize(tot = sum(!!myenc))
    }
    
    sumByColumn(data, b)
    ## A tibble: 2 x 2
    #      a   tot
    #  <int> <int>
    #1     1    24
    #2     2    27
    

    【讨论】:

    • 这行得通……但是,如果我在group_by 之前添加filter( !!myenc &gt; 7 ) ,它不会返回任何行。在 filter() 中指定列名的正确方法是什么?
    • 这是文档的一部分。而不是!!(这是一个方便的函数,不能使用逻辑向量),而是使用UQ,这是正确的函数。即filter(UQ(myenc) &gt; 7)。然后它工作正常。
    【解决方案3】:

    dplyr 现在还为此提供了帮助函数(summarise_at,它接受参数 varsfuns

    sumByColumn <- function(df, colName) {
      df %>%
        group_by(a) %>%
        summarize_at(vars(colName), funs(tot = sum))
    }
    

    提供相同的答案

    # A tibble: 2 x 2
          # a   tot
      # <int> <int>
    # 1     1    24
    # 2     2    27
    

    【讨论】:

    • 注意最后一行可能是:summarize_at(colName, sum)
    • @G.Grothendieck, funs(tot = sum) 以防 OP 想要重命名该列