Как оценить вызов в data.frame?

В одном пакете, над которым я работаю, я столкнулся с проблемой, которая выглядит простой, но я не могу в ней разобраться:

Подфункции передаются два аргумента:

  • obj, a data.frame
  • foo, a call

Например:

> head(obj)
  cadmium copper lead zinc  elev
1    11.7     85  299 1022 7.909
2     8.6     81  277 1141 6.983
3     6.5     68  199  640 7.800
4     2.6     81  116  257 7.655
5     2.8     48  117  269 7.480
6     3.0     61  137  281 7.791
> foo
log(cadmium)
> class(foo)
[1] "call"

В этом примере я хочу создать вектор x <- log(obj$cadmium). Как я могу это сделать? Я пытался использовать with(), но не получил ожидаемого результата:

> with(obj, foo)
log(cadmium)

foo — это вызов, созданный пользователем путем указания преобразования в столбце data.frame obj:

my_function(obj, foo = log(cadmium)) { ... }

dput() фрагмента данных:

obj <- structure(list(cadmium = c(11.7, 8.6, 6.5, 2.6, 2.8, 3), copper = c(85L, 
81L, 68L, 81L, 48L, 61L), lead = c(299L, 277L, 199L, 116L, 117L, 
137L), zinc = c(1022L, 1141L, 640L, 257L, 269L, 281L), elev = c(7.909, 
6.983, 7.8, 7.655, 7.48, 7.791)), .Names = c("cadmium", "copper", 
"lead", "zinc", "elev"), class = "data.frame", row.names = c("1", 
"2", "3", "4", "5", "6"))

person Pierre    schedule 28.06.2011    source источник
comment
Ваш вопрос неполный - вам нужно показать, как был создан foo; Я должен был угадать что-то в своем ответе.   -  person Gavin Simpson    schedule 29.06.2011
comment
Действительная точка. Я добавил некоторые детали. Надеюсь, теперь это легче понять.   -  person Pierre    schedule 29.06.2011


Ответы (3)


Вам нужно оценить вызов, например, используя eval():

foo <- call("log", quote(cadmium))
with(obj, eval(foo))

который дает:

> with(obj, eval(foo))
[1] 2.4595888 2.1517622 1.8718022 0.9555114 1.0296194 1.0986123

где obj – фрагмент показанных вами данных.

eval() также имеет аргумент envir, указывающий среду, в которой оценивается выражение. Таким образом, вы можете делать то, что хотите, без with(), используя eval() напрямую:

> eval(foo, envir = obj)
[1] 2.4595888 2.1517622 1.8718022 0.9555114 1.0296194 1.0986123
person Gavin Simpson    schedule 28.06.2011
comment
Вы действительно любите использовать с! Я рекомендую прочитать with.default, чтобы вы могли выполнять операции напрямую. - person hadley; 29.06.2011
comment
@hadley Вы имеете в виду прямое использование eval(substitute(foo), obj, enclos = parent.frame())? Любая мотивация для этого? - person Pierre; 29.06.2011
comment
@hadley, чтобы быть справедливым, with() здесь было использование, запрошенное OP, которое я затем упростил до использования eval() напрямую. Но да, мне нравится with(), хотя и не за такие вещи... - person Gavin Simpson; 29.06.2011
comment
Пьер Да, foo является аргументом вашей функции, поэтому выполнение того, что делает with(), сэкономит вам дополнительный вызов функции. Вам не нужно указывать enclose. - person Gavin Simpson; 29.06.2011

Что-то типа

z <- data.frame(a1=1:5,b1=LETTERS[1:5],c1=letters[1:5])
foo <- quote(log(a1))
eval(foo,envir=z)

но будьте осторожны: как только вы начинаете использовать eval, вы спускаетесь в более низкие глубины R. Я до сих пор не полностью понимаю различия между вызывающими фреймами, включающими фреймами и т. д. и т. д. ...

person Ben Bolker    schedule 28.06.2011

Не похоже, что вы правильно определили функцию:

> foo <- function(x) log(x)
> class(foo)
[1] "function"

Затем выполните:

x <- foo(obj$cadmium)

Or:

x <- foo(obj[["cadmium"]])

Or:

x <- with(obj, foo(cadmium)
person IRTFM    schedule 28.06.2011
comment
Извините, я, возможно, дал слишком мало деталей. Функция, над которой я работаю, может принимать вызовы. Например, если я хочу построить логарифм значений кадмия, доступ к которым осуществляется из столбца cadmium кадра данных obj, я хочу, чтобы пользователь мог использовать следующий синтаксис (вдохновленный ggplot2): my_function(obj, colours = log(cadmium). - person Pierre; 29.06.2011