Низкая производительность при использовании rbfdot из пакета kernlab в цикле - PullRequest
2 голосов
/ 06 января 2012

Упрощенный пример моего медленно работающего кода (функция rbf из пакета kernlab), который нужно ускорить:

install.packages('kernlab')       
library('kernlab')

rbf <- rbfdot(sigma=1)

test <- matrix(NaN,nrow=5,ncol=10)
for (i in 1:5) {
               for (j in 1:10) { test[i,j] <- rbf(i,j)}
               }

Я пробовал outer(), но это не работает, потому что функция rbf не возвращает необходимую длину (50). Мне нужно ускорить этот код, потому что у меня есть огромное количество данных. Я читал, что векторизация была бы святым Граалем для ускорения этого, но я не знаю как.

Не могли бы вы указать мне правильное направление?

Ответы [ 2 ]

8 голосов
/ 06 января 2012

Если rbf действительно является возвращаемым значением при вызове rbfdot, то body(rbf) выглядит примерно так:

{
    if (!is(x, "vector")) 
        stop("x must be a vector")
    if (!is(y, "vector") && !is.null(y)) 
        stop("y must a vector")
    if (is(x, "vector") && is.null(y)) {
        return(1)
    }
    if (is(x, "vector") && is(y, "vector")) {
        if (!length(x) == length(y)) 
            stop("number of dimension must be the same on both data points")
        return(exp(sigma * (2 * crossprod(x, y) - crossprod(x) - 
            crossprod(y))))
    }
}

Поскольку большая часть этого состоит из функций проверки, а crossprod упрощается, когда вы передаете только скаляры, я думаю, что ваша функция упрощается до

rbf <- function(x, y, sigma = 1)
{
  exp(- sigma * (x - y) ^ 2)
}

Для возможного дальнейшего ускорения используйте пакет compiler (требуется R-2.14.0 или более поздняя версия).

rbf_loop <- function(m, n)
{
  out <- matrix(NaN, nrow = m, ncol = n)
  for (i in seq_len(m)) 
  {
    for (j in seq_len(n)) 
    { 
      out[i,j] <- rbf(i,j)
    }
  }
  out
)

library(compiler)
rbf_loop_cmp <- cmpfun(rbf_loop)

Затем сравните время rbf_loop_cmp(m, n) с тем, что было раньше.


Шаг упрощения легче увидеть наоборот. Если вы развернете (x - y) ^ 2, вы получите x ^ 2 - 2 * x * y + y ^ 2, что минус вещь в функции rbf.

1 голос
/ 07 января 2012

Используйте функцию kernelMatrix () в kernlab, это должно быть пара на пару порядков быстрее, чем зацикливание на функции ядра:

library(kernlab)

rbf <- rbfdot(sigma=1)

kernelMatrix(rbf, 1:5, 1:10)
...