Получите внутренние функции 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.
- Вызов
quantile(instance, 0.5)
отправляется в - Внутри
quantile,MyClass-method
, кодcallNextMethod(x@x, ...)
будет отправлен с содержимым слотаx
как аргумент . Этот аргумент является числовым. - Внутри
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