现在我正在尝试将某些dplyr动作封装到自己的函数中。我遇到的问题是,我不确定如何传递符号,以便他们在适当的时候进行评估。
考虑以下设计的例子,我试图找到从这个数据按降序排序的前n项:
data = tibble(n = seq(10), unif = runif(10), norm = rnorm(10))
使用dplyr,我可以编写以下内容来查找前三名:
data %>% top_n(3, unif) %>% arrange(desc(unif))
现在说我想把它封装成一个函数。天真地,人们可能会尝试跟随,因为col
的值将被传递,所以会失败:
top_n_sorted = function(tbl, n, col) {
# How do I pass col as its name here?
return(
tbl %>%
top_n(n, col) %>%
arrange(desc(col))
)
}
data %>% top_n(3, unif) %>% arrange(desc(unif))
# => KABOOM: object 'unif' not found.
我认为也许通过引用的值(通过替换或引用)可以做到这一点,但它显然从未被dplyr函数打开:
top_n_sorted = function(tbl, n, col) {
return(
tbl %>%
top_n(n, quote(col)) %>%
arrange(desc(quote(col)))
)
}
data %>% top_n(3, unif) %>% arrange(desc(unif))
# => KABOOM: object of type 'symbol' is not subsettable.
我已经挖掘了Hadley的article on metaprogramming,虽然我理解如何在我自己的函数的上下文中使用quote,substitute和eval,但我不确定如何将符号向前传递给其他函数使用像dplyr那样的技巧。
答案 0 :(得分:1)
答案 1 :(得分:0)
其他答案更好,更简单,但一般来说,您可以通过创建字符串并使用eval(parse(text=...))
来评估它,从而制作出您想要的任何表达式。如果问题变得有点复杂并且您需要更快而不是更晚的事情,这可能会很方便。
下面我只是将col粘贴到我们想要的位置,它会吐出实际值并对其进行评估。这确实需要我在引号中输入它而不是作为符号。
top_n_sorted = function(tbl, n, col) {
return(
eval(
parse(
text = paste0('tbl %>% top_n(n, "', col, '") %>% arrange(desc(', col, '))')
)
)
)
}
data %>% top_n_sorted(3, "unif")
答案 2 :(得分:-1)
老实说,我并没有真正得到dplyr
中的非标准评估,特别是当你想知道如何传递输入时。但是,在大多数情况下,当unquoting似乎破坏了东西时,我发现只是将变量名称作为字符串起作用。通常我发现,只要你知道它是一个字符串,直到你把它赋予一个dplyr
函数,它可以接受变量名或的名字作为字符串,事情就不会出错。
这是一个适用于您的第一个函数的示例,例如。唯一的区别是将参数col
设为"unif"
而不是unif
。这并不总是有效,但您没有无法使用此解决方法的情况。
top_n_sorted = function(tbl, n, col) {
tbl %>%
top_n(n, col)) %>%
arrange(desc(col))
}
top_n_sorted(data, 3, "unif")