2011-05-31 15 views
8

Standardowe wyrażenie R outer(X, Y, f) oznacza macierz, której pozycja (i, j) ma wartość f(X[i], Y[j]).Jak generalizować zewnętrzne do n wymiary?

ja do zaimplementowania funkcji multi.outer, n-wymiarowej uogólnienie outer: multi.outer(f, X_1, ..., X_n), w którym część f jest funkcją N-ary, by wytworzyć (długość (X_1) * ... * długość (X_n)) array, której (i_1, ..., i_n) -th pozycja ma wartość f(X_1[i_1], ..., X_n[i_n]) dla wszystkich poprawnych zestawów indeksów (i_1, ..., i_n). Oczywiście, dla każdego i w {1, ..., n}, wszystkie elementy X_i w multi.outer(f, X_1,...,X_i,..., X_n) muszą być dopuszczalnymi i-tymi argumentami dla funkcji f. W przypadku n = 2, multi.outer zrobiłoby to samo co outer, chociaż miałby inną sygnaturę (IOW, multi.outer(f, X, Y) byłaby odpowiednikiem outer(X, Y, f)).

Należy zauważyć, że chociaż argumenty X_1, ..., X_n z multi.outer są wektorem, to niekoniecznie wszystkie mają ten sam tryb. Na przykład. X_1 i X_2 mogą być odpowiednio c(1, 2, 3) i LETTERS[10:20].

Dzięki!

Odpowiedz

16

Jest to jeden sposób: Pierwsze użycie Vectorize i outer zdefiniować funkcję, która tworzy n-wymiarowej macierzy, gdzie każdy wpis jest lista argumentów, na których dana funkcja być stosowane:

list_args <- Vectorize(function(a,b) c(as.list(a), as.list(b)), 
         SIMPLIFY = FALSE) 


make_args_mtx <- function(alist) { 
    Reduce(function(x, y) outer(x, y, list_args), alist) 
} 

teraz multi.outer prostu musi powołać applydo.call i na tej "args matrix":

multi.outer <- function(f, ...) { 
    args <- make_args_mtx(list(...)) 
    apply(args, 1:length(dim(args)), function(a) do.call(f, a[[1]])) 
} 

Spróbujmy to z funkcją np:

fun <- function(a,b,c) paste(a,b,c) 

ans <- multi.outer(fun, LETTERS[1:2], c(3, 4, 5), letters[6:7]) 

> ans 
, , 1 

    [,1] [,2] [,3] 
[1,] "A 3 f" "A 4 f" "A 5 f" 
[2,] "B 3 f" "B 4 f" "B 5 f" 

, , 2 

    [,1] [,2] [,3] 
[1,] "A 3 g" "A 4 g" "A 5 g" 
[2,] "B 3 g" "B 4 g" "B 5 g" 
+0

Nice! Zobacz podobne (ale nie tak skomplikowane) pytanie z podobną odpowiedzią tutaj: http: // stackoverflow.com/questions/5233308/is-there-a-r-function-to-apply-a-function-to-each-pair-of-columns/5233713 # 5233713 – Aaron

1

Jak o tym:


multi.outer<-function(f,...){ 

    apply(expand.grid(...),1,function(x){do.call(f,as.list(x))}) 

} 
+0

Uważam, że OP chciał, aby wynik był w macierzy n-wymiarowej, z każdym wymiarem odpowiadającym każdemu z argumentów "f". –

+0

+1 za poinformowanie mnie o 'expand.grid', ale kiedy spróbowałem tego' multi.outer' (po raz pierwszy) z funkcją testową 'funkcja (s, b, l) {substr (s, b, b + l - 1)} ', a' c ("ABCDEFGH", "IJKLMNOP", "QRSTUVWX"), 1: 5, 2: 3' jako pozostałe argumenty, otrzymałem komunikat "Błąd w funkcji (s, b, l): nieużywany argument (y) (Var1 = "ABCDEFGH", Var2 = "1", Var3 = "2") '. Nie miałem okazji dowiedzieć się, co robi twoja implementacja ani dlaczego ten błąd. – kjo

0

myślę, że możemy to zrobić za pomocą zewnętrznego oraz wektoryzacji.

sigm = function(a=0,b=0,x){ 
return(exp(x*a+b)) 
} 

sigm1 = Vectorize(function(a=-1:1,b=-1:1,x){ 

outer(a,b,sigm,x) 
},SIMPLIFY = FALSE) 

Teraz sigm1 (x = 1: 3) daje wymaganą moc

[[1]] 
     [,1]  [,2]  [,3] 
[1,] 0.1353353 0.3678794 1.000000 
[2,] 0.3678794 1.0000000 2.718282 
[3,] 1.0000000 2.7182818 7.389056 

[[2]] 
     [,1]  [,2]  [,3] 
[1,] 0.04978707 0.1353353 0.3678794 
[2,] 0.36787944 1.0000000 2.7182818 
[3,] 2.71828183 7.3890561 20.0855369 

[[3]] 
     [,1]  [,2]  [,3] 
[1,] 0.01831564 0.04978707 0.1353353 
[2,] 0.36787944 1.00000000 2.7182818 
[3,] 7.38905610 20.08553692 54.5981500 

jedynie wyciągnąć z powrotem z tego fragmentu ja użyciu domyślnych wartości a = 1: 1 i b = -1: 1. Kiedy próbuję przekazać to samo podczas wywoływania funkcji, to idzie w szał. Na przykład.

sigm1(-1:1,-1:1,1:3) 

[[1]] 
     [,1] 
[1,] 0.1353353 

[[2]] 
[,1] 
[1,] 1 

[[3]] 
    [,1] 
[1,] 54.59815 

Nie jestem w stanie zrozumieć, dlaczego przekazywanie argumentów powoduje tę różnicę w wynikach.