【问题标题】:character string as function argument r字符串作为函数参数 r
【发布时间】:2014-09-23 07:44:33
【问题描述】:

我正在使用 dplyr 并创建代码来计算用 ggplot 绘制的新数据。

我想用这段代码创建一个函数。它应该采用由 dplyr 操作的数据框列的名称。但是,尝试使用列名不起作用。请考虑下面的最小示例:

df <- data.frame(A = seq(-5, 5, 1), B = seq(0,10,1))

library(dplyr)
foo <- function (x) {
         df %>%
            filter(x < 1)
}

foo(B)

Error in filter_impl(.data, dots(...), environment()) : 
  object 'B' not found 

有什么办法可以将列名作为函数参数使用吗?

【问题讨论】:

  • 你能提出你的问题reproducible吗?此时您正在提供一个所有(两个)值都高于 1 的数据框。
  • 感谢 Jaap 的建议,我编辑了 df 以确保可重复性
  • 我记得@Richard Scriven 回答了一个类似的问题。我认为你需要写类似foo &lt;- function(x,...)filter(x,...) 的东西我现在有以下内容。不知道我写的东西是否正确。但结果似乎是对的。foo &lt;- function (x,...) filter(x,...);foo(df, B &lt; 1)
  • @jazzurro,很遗憾我无法复制您的建议。也许您可以提供可重现的示例。
  • @jnshsrs 我使用了你的 df 并运行了代码。 R 返回第一行。你能在你的机器上用你的 df 运行代码吗?

标签: r string function character dplyr


【解决方案1】:

如果你想创建一个接受字符串“B”作为参数的函数(如你的问题标题)

foo_string <- function (x) {
         eval(substitute(df %>% filter(xx < 1),list(xx=as.name(x))))
}
foo_string("B")

如果你想创建一个接受捕获 B 作为参数的函数(如在 dplyr 中)

foo_nse <- function (x) {
         # capture the argument without evaluating it
         x <- substitute(x)
         eval(substitute(df %>% filter(xx < 1),list(xx=x)))
}
foo_nse(B)

您可以在Advanced R找到更多信息

编辑

dplyr 在 0.3 版中让事情变得更容易。带有后缀“_”的函数接受字符串或表达式作为参数

 foo_string <- function (x) {
             # construct the string
             string <- paste(x,"< 1")
             # use filter_ instead of filter
             df %>% filter_(string)
    }
foo_string("B")
 foo_nse <- function (x) {
             # capture the argument without evaluating it
             x <- substitute(x)
             # construct the expression
             expression <- lazyeval::interp(quote(xx < 1), xx = x)
             # use filter_ instead of filter
             df %>% filter_(expression)
    }
foo_nse(B)

你可以在这个vignette找到更多信息

【讨论】:

  • 感谢您提供更多信息。这对我很有用。
【解决方案2】:

我记得@Richard Scriven 回答了一个类似的问题。我认为你需要写这样的东西。

foo <- function(x,...)filter(x,...) 

@Richard Scriven 提到的是你需要在这里使用...。如果您键入 ?dplyr,您将能够找到:filter(.data, ...) 我认为您将 .data 替换为 x 或其他内容。如果你想在你的df中选择B中值小于1的行,它会是这样的。

foo <- function (x,...) filter(x,...)
foo(df, B < 1)

【讨论】:

  • 我一定老了。我不记得这件事了。但是 +1,因为它有效!
  • @RichardScriven 我可能是错的。但是,我认为是您使用select() 回答了类似的问题。那是我的灵感。上面的代码有效,但是当我看到它时我很惊讶。