2009-11-12 8 views
7

rozumiem jak zewnętrzna() działa w R:zewnętrzna() odpowiednik dla list zakaz wektorowych w R

> outer(c(1,2,4),c(8,16,32), "*") 

    [,1] [,2] [,3] 
[1,] 8 16 32 
[2,] 16 32 64 
[3,] 32 64 128 

To w zasadzie trwa 2 wektorów, znajdzie iloczyn wektorowy tych wektorów, a następnie stosuje się funkcję każda para w crossproduct.

Nie mam jednak dwóch wektorów. Mam dwie listy macierzy:

M = lista();

M[[1]] = matrix(...) 
M[[2]] = matrix(...) 
M[[3]] = matrix(...) 

I chcę wykonać operację na mojej liście matriks. Chcę zrobić:

outer(M, M, "*") 

W tym przypadku chcę wziąć iloczyn kropek z każdej kombinacji macierzy, które mam.

Faktycznie, próbuję wygenerować macierz jądra (i pisałem funkcji jądra), więc chcę zrobić:

outer(M, M, kernelFunction) 

gdzie kernelFunction oblicza odległość między moimi dwoma matrycami.

Problem polega na tym, że outer() pobiera tylko argumenty "wektorowe", a nie "listy" itp. Czy istnieje funkcja równoważąca zewnętrzną() dla elementów innych niż wektorowe?

Alternatywnie, można użyć pętli for, aby to zrobić:

M = list() # Each element in M is a matrix 

for (i in 1:numElements) 
{ 
    for (j in 1:numElements) 
    { 
     k = kernelFunction(M[[i]], M[[j]]) 
     kernelMatrix[i,j] = k; 
    } 
} 

ale staram się tego uniknąć za konstruktem R (który może być bardziej wydajny). (Tak, wiem, że mogę zmodyfikować pętlę for w celu obliczenia macierzy diagonalnej i zaoszczędzić 50% obliczeń, ale to nie jest kod, który próbuję zoptymalizować!)

Czy to możliwe? Wszelkie przemyślenia/sugestie?

Odpowiedz

10

Wystarczy użyć pętli for. Wszelkie wbudowane funkcje i tak ulegną degeneracji, a stracisz wyrazistość wypowiedzi, chyba że ostrożnie zbudujesz funkcję, która generalizuje zewnętrzne do pracy z listami.

Największą poprawę można zrobić byłoby przydzielenia matrycy:

M <- list() 
length(M) <- numElements^2 
dim(M) <- c(numElements, numElements) 

PS. Lista jest wektorem.

13

Funkcja zewnętrzna faktycznie działa na listach, ale funkcja, że ​​podasz dostaje dwa wektory wejściowe powtarzane tak, że zawierają one wszystkie możliwe kombinacje ...

chodzi o które jest szybsze, łącząc zewnętrzna jest z vapply 3 razy szybciej niż podwójna pętla for na moim komputerze. Jeśli rzeczywista funkcja jądra działa "prawdziwie", różnica w szybkości pętli nie jest prawdopodobnie tak ważna.

f1 <- function(a,b, fun) { 
    outer(a, b, function(x,y) vapply(seq_along(x), function(i) fun(x[[i]], y[[i]]), numeric(1))) 
} 

f2 <- function(a,b, fun) { 
    kernelMatrix <- matrix(0L, length(a), length(b)) 
    for (i in seq_along(a)) 
    { 
     for (j in seq_along(b)) 
     { 
      kernelMatrix[i,j] = fun(a[[i]], b[[j]]) 
     } 
    } 
    kernelMatrix 
} 

n <- 300 
m <- 2 
a <- lapply(1:n, function(x) matrix(runif(m*m),m)) 
b <- lapply(1:n, function(x) matrix(runif(m*m),m)) 
kernelFunction <- function(x,y) 0 # dummy, so we only measure the loop overhead 

> system.time(r1 <- f1(a,b, kernelFunction)) 
    user system elapsed 
    0.08 0.00 0.07 
> system.time(r2 <- f2(a,b, kernelFunction)) 
    user system elapsed 
    0.23 0.00 0.23 
> identical(r1, r2) 
[1] TRUE 
3

Chociaż jest to stare pytanie, oto inne rozwiązanie, które jest bardziej zgodne z duchem zewnętrznej funkcji. Chodzi o to, aby zastosować zewnętrzne wzdłuż indeksów z listy 1 i listy2:

cor2 <- Vectorize(function(x,y) { 
    vec1 <- list1[[x]] 
    vec2 <- list2[[y]] 
    cor(vec1,vec2,method="spearman") 
}) 
outer(1:length(list1), 1:length(list2), cor2) 
Powiązane problemy