диспетчеризация методов S4 с выражением в качестве аргумента - PullRequest
11 голосов
/ 09 августа 2011

Я пытаюсь убедить метод 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: изменено для преобразования, так как это лучший пример.

Ответы [ 2 ]

2 голосов
/ 10 сентября 2011

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

NewVar=Petal.Width*Petal.Length

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

Petal.Width*Petal.Length

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

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

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

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

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

Я думаю, что это только частично отвечает на ваш вопрос, потому что тривиальный возврат iris data.frame был не тем, что вы хотели. Выражение не оценивается должным образом с помощью 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

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

Всегда есть стандарт ..., если вы не хотите отправлять на 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" "Виды"

По сути, часть выражения "NewVar =" не была передана transform (), когда мы вызвали 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", который мы хотели.

1 голос
/ 09 августа 2011

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

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

Я также думаю, что вызов внутри функции не будет заменой в вызывающей функции ...

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

...