Отправка S4-методов с выражением в качестве аргумента

Я пытаюсь убедить S4-метод использовать выражение в качестве аргумента, но всегда получаю сообщение об ошибке. Тривиальный пример, который немного иллюстрирует то, что я пытаюсь сделать здесь:

setGeneric('myfun',function(x,y)standardGeneric('myfun'))

setMethod('myfun',c('data.frame','expression'),
          function(x,y) transform(x,y) )

Если я сейчас попробую:

> myfun(iris,NewVar=Petal.Width*Petal.Length)
Error in myfun(iris, NewVar = Petal.Width * Petal.Length) : 
  unused argument(s) (NewVar = Petal.Width * Petal.Length)

> myfun(iris,{NewVar=Petal.Width*Petal.Length})
Error in myfun(iris, list(NewVar = Petal.Width * Petal.Length)) : 
 error in evaluating the argument 'y' in selecting a method for 
 function 'myfun': Error: object 'Petal.Width' not found

Кажется, что аргументы оцениваются в родовом уже, если я это правильно понимаю. Таким образом, передача выражений до методов кажется, по крайней мере, сложной. Есть ли возможность использовать методы отправки S4 с помощью выражений?


edit: изменено для преобразования, поскольку это лучший пример.

Ответ 1

Вы указали "выражение" как класс второго аргумента в этом примере. Первый пример возвращает ошибку, поскольку

NewVar=Petal.Width*Petal.Length

интерпретируется как именованный аргумент myfun со значением

Petal.Width*Petal.Length

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

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

Ошибка в myfun (iris, {: ошибка в оценке аргумента 'y' при выборе метода для функции 'myfun': Ошибка: объект 'Petal.Width' не найден

Однако я не получаю ошибки и получаю iris data.frame как вывод, когда я заставляю ваше выражение быть объектом выражения:

myfun(iris, expression(NewVar=Petal.Width*Petal.Length))

Я думаю, что это лишь частично отвечает на ваш вопрос, потому что тривиальное возвращение данных диафрагмы. Это не то, что вы хотели. Выражение не оценивается должным образом методом transform(). Я подозреваю, что вы хотите, чтобы результат точно соответствовал выводам из следующей версии с жестким кодированием:

transform(iris, NewVar=Petal.Width*Petal.Length)

Вот краткий пример оценки выражения с использованием eval

z <- expression(NewVar = Petal.Width*Petal.Length)
test <- eval(z, iris)
head(test, 2)

[1] 0,28 0,28

Вот версия, которая работает для добавления одного столбца переменной в файл data.frame:

setGeneric('myfun',function(x,y)standardGeneric('myfun'))
setMethod('myfun',c('data.frame','expression'), function(x,y){
    etext <- paste("transform(x, ", names(y), "=", as.character(y), ")", sep="")
    eval(parse(text=etext))
})
## now try it.
test <- myfun(iris, expression(NewVar=Petal.Width*Petal.Length))
names(test)

[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Породы" "NewVar"

head(test)

    Sepal.Length Sepal.Width Petal.Length Petal.Width Species NewVar
1          5.1         3.5          1.4         0.2  setosa   0.28
2          4.9         3.0          1.4         0.2  setosa   0.28

Опять же, эта реализация по существу жестко закодирована, что один и только один столбец переменной будут добавлены во входной файл данных, хотя имя столбца этой переменной и выражение произвольны и представлены как выражение. Я уверен, что есть лучший, более общий ответ, который оценил бы выражение, содержащееся в y, как если бы это был прямой вызов в функции transform(), но в настоящий момент я озадачен тем, что использовать в качестве подходящего "обратного" function to expression().

Всегда есть стандарт..., если вы действительно не хотите отправлять y:

setGeneric('myfun', function(x, ...) standardGeneric('myfun'))
setMethod('myfun', 'data.frame', function(x, ...){
    transform(x, ...)
})

И это отлично работает. Но ваш вопрос заключался в том, чтобы фактически отправлять объект выражения.

Следующее не работает, но я думаю, что он приближается. Возможно, кто-то может вскочить и сделать некоторые окончательные настройки:

setGeneric('myfun', function(x, y) standardGeneric('myfun'))
setMethod('myfun',c('data.frame', 'expression'), function(x, y){
    transform(x, eval(y, x, parent.frame()))
})
## try out the new method
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- myfun(iris, z)
names(test)

[1] "Sepal.Length" "Sepal.Width" "Petal.Length" "Petal.Width" "Species"

По существу, часть "NewVar =" выражения не передавалась преобразованию(), когда мы вызывали myfun().

После долгих проб и ошибок я понял, как это работает. Сначала преобразуйте объект выражения в список с помощью as.list(), а затем создайте вызов, который вы хотите, с чудесным

do.call()

Полный пример выглядит следующим образом:

setGeneric('myfun', function(x, y) standardGeneric('myfun'))
setMethod('myfun',c('data.frame', 'expression'), function(x, y){
    do.call("transform", c(list(x), as.list(y)))
})
# try out the new method
z <- expression(NewVar = Petal.Width*Petal.Length)
test <- myfun(iris, z)
names(test)
[1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"     
[6] "NewVar"

И новый объект data.frame "test" имеет нужный столбец "NewVar".

Ответ 2

Это не S4 или оценка аргумента, что R не может определить, хотите ли вы передать именованный параметр или если ваше выражение имеет вид a = b.

Если вы посмотрите на справку для "внутри", она использует фигурные скобки, чтобы убедиться, что выражение анализируется как выражение.

Я также думаю, что вызов внутри внутри функции не будет выполнять замену в функции caller...

Я также думаю, что не знаю достаточно о выражениях.