【问题标题】:Passing a variable for a column name?为列名传递变量?
【发布时间】:2017-09-24 07:24:08
【问题描述】:

例如,假设您有一个应用了一些 DPLYR 函数的函数,但您不能期望传递给该函数的数据集具有相同的列名。

对于我的意思的简化示例,假设您有一个数据框,arizona.trees

arizona.trees
group arizona.redwoods   arizona.oaks 
A     23                 11        
A     24                 12  
B     9                  8 
B     10                 7
C     88                 22

和另一个非常相似的数据框,california.trees:

california.trees
group    california.redwoods california.oaks 
A        25                  50        
A        11                  33  
B        90                  5 
B        77                  3
C        90                  35

并且您想要实现一个函数,该函数返回给定类型的树的给定组(A、B、... Z)的平均值,该树适用于这两个数据帧。

foo <- function(dataset, group1, group2, tree.type) { 
     column.name <- colnames(dataset[2])
     result <- filter(dataset, group %in% c(group1, group2) %>%
               select(group, contains(tree.type)) %>%
               group_by(group) %>%
               summarize("mean" = mean(column.name))
     return(result)
}

foo(california.trees, A, B, redwoods) 调用的期望输出是:

result
       mean
A       18
B       83.5

出于某种原因,执行foo() 之类的操作似乎不起作用。这可能是由于数据框索引的一些错误 - 该函数似乎认为我正在尝试获取column.name 字符串的平均值,而不是检索列并将列传递给mean()。我不确定如何避免这种情况。存在隐式传递修改后的数据帧的问题,可能导致问题的管道运算符无法直接引用该数据帧。

这是为什么?有没有其他可行的实现方式?

【问题讨论】:

标签: r variables dplyr


【解决方案1】:

我们可以使用dplyr 开发版中基于quosure 的解决方案(即将发布0.6.0

foo <- function(dataset, group1, group2, tree.type){
        group1 <- quo_name(enquo(group1))
         group2 <- quo_name(enquo(group2))
         colN <- rlang::parse_quosure(names(dataset)[2])
         tree.type <- quo_name(enquo(tree.type))
        dataset %>%
                filter(group %in% c(group1, group2)) %>%
                select(group, contains(tree.type)) %>%
                group_by(group) %>%
                summarise(mean = mean(UQ(colN)))
        }


foo(california.trees, A, B, redwoods)
# A tibble: 2 × 2
#  group  mean
#  <chr> <dbl>
#1     A  18.0
#2     B  83.5

foo(arizona.trees, A, B, redwoods)
# A tibble: 2 × 2
#   group  mean
#  <chr> <dbl>
#1     A  23.5
#2     B   9.5

enquo接受输入参数并将其转换为quosure,与quo_name一起转换为字符串以与%in%一起使用,第二列名称从使用@的字符串转换为quosure 987654331@,然后在 summarise 内不引用(UQ!!)进行评估

注意:这是基于 OP 关于选择第二列的功能


上述解决方案基于根据位置选择列(根据 OP 的代码),它可能不适用于其他列。因此,我们可以匹配 'tree.type' 并据此获取列的 'mean'

foo1 <- function(dataset, group1, group2, tree.type){

        group1 <- quo_name(enquo(group1))
         group2 <- quo_name(enquo(group2))


         tree.type <- quo_name(enquo(tree.type))
        dataset %>%
                filter(group %in% c(group1, group2)) %>%
                select(group, contains(tree.type)) %>%
                group_by(group) %>%
                summarise_at(vars(contains(tree.type)), funs(mean = mean(.)))
        }

函数可以针对两个数据集中的不同列进行测试

foo1(arizona.trees, A, B, oaks)
# A tibble: 2 × 2
#  group  mean
#   <chr> <dbl>
#1     A  11.5
#2     B   7.5

foo1(arizona.trees, A, B, redwood)
# A tibble: 2 × 2
#  group  mean
#   <chr> <dbl>
#1     A  23.5
#2     B   9.5

foo1(california.trees, A, B, redwood)
# A tibble: 2 × 2
#  group  mean
#   <chr> <dbl>
#1     A  18.0
#2     B  83.5

foo1(california.trees, A, B, oaks)
# A tibble: 2 × 2
#  group  mean
#  <chr> <dbl>
#1     A  41.5
#2     B   4.0

数据

arizona.trees <- structure(list(group = c("A", "A", "B", "B", "C"), 
arizona.redwoods = c(23L, 
24L, 9L, 10L, 88L), arizona.oaks = c(11L, 12L, 8L, 7L, 22L)),
.Names = c("group", 
"arizona.redwoods", "arizona.oaks"), class = "data.frame",
 row.names = c(NA, -5L))

california.trees <- structure(list(group = c("A", "A", "B", "B", "C"), 
 california.redwoods = c(25L, 
11L, 90L, 77L, 90L), california.oaks = c(50L, 33L, 5L, 3L, 35L
)), .Names = c("group", "california.redwoods", "california.oaks"
), class = "data.frame", row.names = c(NA, -5L))

【讨论】:

  • 感谢您的快速回复!如果不使用dplyr的开发版,有没有办法做这样的事情?
  • @user3450277 开发版即将发布为 0.6.0。预计在 4 月,可能在 5 月进入 CRAN。否则,您可以使用 summarise_ 等函数,但它们很快就会被弃用。如果您要进行生产级编码,那么最好长期编码
  • 感谢非常详细的回复!
  • 如果您以前没有使用过开发版本,安装它很容易(就像回滚到当前版本一样):install.packages("devtools") # if you haven't 然后devtools::install_github("tidyverse/dplyr") 回滚只是一个正常install.packages("dplyr") 通话。
  • 开发版中的 Tidyeval 功能是您问题的关键:github.com/tidyverse/dplyr/blob/master/NEWS.md#tidyeval
猜你喜欢
  • 2015-11-21
  • 1970-01-01
  • 2017-08-15
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 2013-08-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多