Получите внутренние функции R, чтобы использовать мой метод S4

Я создал собственный класс S4, и идея состоит в том, что он представляет вектор, который всегда отсортирован, поэтому я не хочу ничего с ним делать. Итак, я определил для своего класса заглушку:

      MyClass <- methods::setClass("MyClass", slots=list(x="numeric"))
setMethod("sort", signature(x="MyClass"), function(x, ...){}) # Do nothing

Затем я хочу вычислить квантиль своего класса. Функция R вызывает внутренние вызовы. Тем не менее sort() используется внутри quantile()это не известно о моем методе S4, так как он отправляет с помощью UseMethod()(диспетчер S3) а не standardGeneric(), диспетчер S4. Это показано ниже:

      options(error=traceback)
instance = MyClass()
quantile(instance, 0.5)

Это возвращает стек вызовов, подобный этому:

      5: order(x, na.last = na.last, decreasing = decreasing)
4: sort.default(x, partial = unique(c(lo, hi)))
3: sort(x, partial = unique(c(lo, hi)))
2: quantile.default(instance, 0.5)
1: quantile(instance, 0.5)

С sort.default называется, очевидно, что мой обычай sort реализация не используется.

Есть ли здесь простой способ заставить R использовать мой метод S4? Я понимаю, что могу также определить sort.MyClass(способ S3), но если я сделаю это, какой смысл вообще использовать метод S4? Похоже, что S4 несовместим с основными методами R, что делает его бесполезным.

1 ответ

Объектinstanceопределяется слотом с числовым именем. Когда вы звоните, R не знает, что вы хотите действовать на слотеinstance@x.
Подход 1:

      MyClass <- setClass("MyClass", slots = list(x = "numeric"))

setMethod(
    "quantile",
    signature(x = "MyClass"),
    function(x, ...) {
        callNextMethod(x@x, ...)
    }
)

# test drive
instance <- MyClass(x = c(0, 5, 2, 1, 3))
quantile(instance, 0.5)
sort(instance) # error
mean(instance) # error

# see that quantile is now using S4 dispatch
quantile
standardGeneric for "quantile" defined from package "stats"

function (x, ...) 
standardGeneric("quantile")
<environment: 0x000001fe1375fe08>
Methods may be defined for arguments: x
Use  showMethods(quantile)  for currently available ones.

# see method table for quantile
showMethods(quantile, includeDefs = TRUE)
Function: quantile (package stats)
x="ANY"
function (x, ...) 
UseMethod("quantile")


x="MyClass"
function (x, ...) 
{
    callNextMethod(x@x, ...)
}

При таком подходе вы можете видеть, чтоquantileавтоматически преобразуется в использование диспетчеризации S4.

  1. Вызовquantile(instance, 0.5)отправляется в
  2. Внутриquantile,MyClass-method, кодcallNextMethod(x@x, ...)будет отправлен с содержимым слота xкак аргумент . Этот аргумент является числовым.
  3. Внутриquantile,ANY-method, код S3 отправит вызывающие аргументы вquantile.default.

Однако этот подход требует, чтобы вы указали индивидуальную версию каждой функции, с которой нужно работать. Поэтомуsort(instance)иmean(instance)ошибка вывода.

Подход 2 : Сделать как подкласс . Тогда все функции, которые работают на . Ниже я добавляю настроенныйinitializeдля автоматической сортировки числового аргумента. Аsort,MyClass-methodне делать сортировку и только возвращатьMyClassкакnumericдля согласованности.

      MyClass <- setClass("MyClass", contains = "numeric")
setMethod("initialize",
    signature(.Object = "MyClass"),
    function (.Object, ...)
    {      
        callNextMethod(.Object, sort(..1)) # ..1 is first element of ... see ?dots
    }
)

setMethod(
    "sort",
    signature(x = "MyClass"),
    function(x, decreasing = FALSE, ...) {
        as(x, "numeric")
    }
)

# test drive
instance <- MyClass(c(0, 5, 2, 1, 3))
quantile(instance, 0.5)
quantile(instance)
mean(instance)
sd(instance)
plot(instance)

Примечание:

      setMethod("sort", signature(x="MyClass"), function(x, ...){}) # return NULL
setMethod("sort", signature(x="MyClass"), function(x, ...) x) # return x unchange
Другие вопросы по тегам