r - 为列名传递变量?

例如,假设您有一个函数应用了一些 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 字符串的平均值,而不是检索该列并将该列传递给 均值()。我不确定如何避免这种情况。存在隐式传递修改后的数据帧的问题,管道运算符无法直接引用可能导致该问题的问题。

这是为什么?是否有一些可行的替代实现方案?

最佳答案

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

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%,第二列名称使用 parse_quosure 从字符串转换为 quosure,然后不加引号(UQ!!) 在 summarise

中进行评估

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


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

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))

https://stackoverflow.com/questions/43641851/

相关文章:

atom-editor - 原子氢 : How is "run cell" used?

docker - 在 alpine 容器中使用 confluent-kafka python 客户端

r - 每种可能组合的 Wilcoxon 秩和检验

azure - 在 Debian 上安装 AzureAD 模块

r - 从 R 中的公式中提取模型框架时排除变量

java - 找不到属性 : Error in spring boot 的设置方法

java - 将 long 列表转换为 double 列表

r - 交叉比较相同数据框的列

junit4 - Wiremock 模拟返回 HTTP 500

java - 使用 lambda 计算列表中的列表