例如,假设您有一个应用了某些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()
。我不确定如何避免这种情况。存在修改的数据帧的隐式传递问题,该问题无法直接引用可能导致问题的管道操作符。
这是为什么?是否有一些可行的替代实现?
答案 0 :(得分:4)
我们可以使用quosure
的devel版本中基于dplyr
的解决方案(即将发布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
从字符串parse_quosure
开始,然后在UQ
!!
或summarise
)进行评估
注意:这是基于OP关于选择第二列的功能
上述解决方案基于根据位置选择列(根据OP的代码),它可能不适用于其他列。所以,我们可以匹配&#39; tree.type&#39;得到“意思是”&#39;基于那个
的列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))