将变量名传递给R中的函数

sta*_*tti 28 r lazy-evaluation

我注意到有很多软件包允许你传递在调用函数的上下文中甚至可能无效的符号名称.我想知道它是如何工作的以及如何在我自己的代码中使用它?

这是ggplot2的一个例子:

a <- data.frame(x=1:10,y=1:10)
library(ggplot2)
qplot(data=a,x=x,y=y)
Run Code Online (Sandbox Code Playgroud)

x并且y在我的命名空间中不存在,但ggplot理解它们是数据框的一部分,并将它们的评估推迟到它们有效的上下文中.我尝试过做同样的事情:

b <- function(data,name) { within(data,print(name)) }
b(a,x)
Run Code Online (Sandbox Code Playgroud)

然而,这失败了:

Error in print(name) : object 'x' not found
Run Code Online (Sandbox Code Playgroud)

我究竟做错了什么?这是如何运作的?

注意:这不是变量名称传递给r中的函数的副本

Jac*_*b H 25

我知道这是一个较旧的主题,但它是我过去提到的.我最近发现了我认为传递变量名称的更好方法.所以我想我会把它包括在内.我希望这可以帮助别人.

a <- data.frame(x = 1:10, y = 1:10)

b <- function(df, name){
    eval(substitute(name), df)
}

b(a, x)
  [1]  1  2  3  4  5  6  7  8  9 10
Run Code Online (Sandbox Code Playgroud)

更新该方法使用非标准评估.我开始解释但很快意识到Hadley Wickham比我做得更好.阅读http://adv-r.had.co.nz/Computing-on-the-language.html

  • 这是一个答案的宝石,谢谢.如果它有帮助,那么如果`var < - eval(substitute(var),data)`给你对象,那么`var.name < - substitute(var)`会给你传递的变量名,以便在函数中使用. (2认同)

ags*_*udy 14

您可以使用match.call例如:

b <-  function(data,name) {

  ## match.call return a call containing the specified arguments 
  ## and the function name also 
  ## I convert it to a list , from which I remove the first element(-1)
  ## which is the function name

  pars <- as.list(match.call()[-1])
  data[,as.character(pars$name)]

}

 b(mtcars,cyl)
 [1] 6 6 4 6 8 6 8 4 4 6 6 8 8 8 8 8 8 4 4 4 4 8 8 8 8 4 4 4 8 6 8 4
Run Code Online (Sandbox Code Playgroud)

说明:

match.call返回一个调用,其中所有指定的参数都由其全名指定.

所以这里的输出match.call是2个符号:

b <-  function(data,name) {
  str(as.list(match.call()[-1]))  ## I am using str to get the type and name
}

b(mtcars,cyl)
List of 2
 $ data: symbol mtcars
 $ name: symbol cyl
Run Code Online (Sandbox Code Playgroud)

那么我使用第一个符号mtcars ansd将第二个转换为字符串:

mtcars[,"cyl"]
Run Code Online (Sandbox Code Playgroud)

或等同于:

eval(pars$data)[,as.character(pars$name)]
Run Code Online (Sandbox Code Playgroud)

  • @static_rtti所以它不够清楚:)它失败了,因为你的数据不包含名为"name"的列.你应该使用`within(data,pars $ name)之类的东西,其中`pars`是使用上面的`match.call`定义的. (2认同)

Kev*_*vin 5

非常旧的线程,但您也可以使用该get命令。它似乎更适合我。

a <- data.frame(x = 1:10, y = 11:20)

b <- function(df, name){

   get(name, df)

 }

b(a, "x")
 [1]  1  2  3  4  5  6  7  8  9 10 
Run Code Online (Sandbox Code Playgroud)