Передача имени переменной в функцию из R

Я заметил, что довольно много пакетов позволяют передавать имена символов, которые могут быть даже недействительными в контексте вызова функции. Мне интересно, как это работает и как я могу использовать его в своем собственном коде?

Вот пример с ggplot2:

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

x и y не существуют в моем пространстве имен, но ggplot понимает, что они являются частью фрейма данных и откладывает их оценку в контексте, в котором они действительны. Я пробовал сделать то же самое:

b <- function(data,name) { within(data,print(name)) }
b(a,x)

Однако это терпит неудачу:

Error in print(name) : object 'x' not found

Что я делаю неправильно? Как это работает?

Примечание: это не дубликат передать имя переменной функции в r

Ответы

Ответ 1

Я знаю, что это более старый поток, но это тот, о котором я упоминал в прошлом. Недавно я обнаружил, что, по моему мнению, лучший подход к передаче имен переменных. Поэтому я подумал, что я включу его. Надеюсь, это поможет кому-то.

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

Обновление. Этот подход использует нестандартную оценку. Я начал объяснять, но быстро понял, что Хэдли Уикхем делает это намного лучше, чем мог. Прочтите этот http://adv-r.had.co.nz/Computing-on-the-language.html

Ответ 2

Вы можете сделать это, используя 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

объяснение:

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

Итак, я использую первый символ mtcars ansd преобразовать второй в строку:

mtcars[,"cyl"]

или эквивалент:

eval(pars$data)[,as.character(pars$name)]

Ответ 3

Если вы поместите имя переменной между кавычками, когда вы вызываете эту функцию, она работает:

> b <- function(data,name) { within(data,print(name)) }
> b(a, "x")
[1] "x"
    x  y
1   1  1
2   2  2
3   3  3
4   4  4
5   5  5
6   6  6
7   7  7
8   8  8
9   9  9
10 10 10