Moja klasa S4 ma metodę, która jest wywoływana wiele razy. Zauważyłem, że czas wykonania jest znacznie wolniejszy niż byłoby, gdyby podobna funkcja została wywołana niezależnie. Dodałem więc slot z typem "function" do mojej klasy i użyłem tej funkcji zamiast metody. Poniższy przykład pokazuje dwa sposoby zrobienia tego, a obie z nich działają znacznie szybciej niż odpowiednia metoda. Również przykład sugeruje, że niższa prędkość metody nie jest spowodowana metodą pobierania danych z klasy, ponieważ funkcje są szybsze nawet wtedy, gdy również to robią.Czy rozsyłanie metodą S4 jest wolne?
Oczywiście ten sposób robienia rzeczy nie jest idealny. Zastanawiam się, czy istnieje sposób na przyspieszenie wysyłki metody. Jakieś sugestie?
setClass(Class = "SpeedTest",
representation = representation(
x = "numeric",
foo1 = "function",
foo2 = "function"
)
)
speedTest <- function(n) {
new("SpeedTest",
x = rnorm(n),
foo1 = function(z) sqrt(abs(z)),
foo2 = function() {}
)
}
setGeneric(
name = "method.foo",
def = function(object) {standardGeneric("method.foo")}
)
setMethod(
f = "method.foo",
signature = "SpeedTest",
definition = function(object) {
sqrt(abs([email protected]))
}
)
setGeneric(
name = "create.foo2",
def = function(object) {standardGeneric("create.foo2")}
)
setMethod(
f = "create.foo2",
signature = "SpeedTest",
definition = function(object) {
z <- [email protected]
[email protected] <- function() sqrt(abs(z))
object
}
)
> st <- speedTest(1000)
> st <- create.foo2(st)
>
> iters <- 100000
>
> system.time(for (i in seq(iters)) method.foo(st)) # slowest by far
user system elapsed
3.26 0.00 3.27
> # much faster
> system.time({foo1 <- [email protected]; x <- [email protected]; for (i in seq(iters)) foo1(x)})
user system elapsed
1.47 0.00 1.46
> # retrieving [email protected] instead of x does not affect speed
> system.time({foo1 <- [email protected]; for (i in seq(iters)) foo1([email protected])})
user system elapsed
1.47 0.00 1.49
> # same speed as foo1 although no explicit argument
> system.time({foo2 <- [email protected]; for (i in seq(iters)) foo2()})
user system elapsed
1.44 0.00 1.45
# Cannot increase speed by using a lambda to "eliminate" the argument of method.foo
> system.time({foo <- function() method.foo(st); for (i in seq(iters)) foo()})
user system elapsed
3.28 0.00 3.29
Dzięki za przydatną sugestię. Powód, dla którego moja reprezentacja danych i metody nie są wektoryzowane: używam polimorfizmu. W moim kodzie mam inną metodę.foo na podklasę, a różni ludzie mogą pisać różne metody. Tak więc, inaczej niż w przykładzie, każde wywołanie metody.foo wywołuje inną metodę i nie wiem, co jest w treści każdej z metod. – Soldalma