2011-05-31 8 views
8

L'espressione R standard outer(X, Y, f) restituisce una matrice la cui voce (i, j) -th ha il valore f(X[i], Y[j]).Come generalizzare l'esterno in n dimensioni?

desidero implementare la funzione multi.outer, una generalizzazione n-dimensionale di outer: multi.outer(f, X_1, ..., X_n), dove f è una funzione n-aria, produrrebbe un (lunghezza (X_1) * ... * lunghezza (X_n)) array la cui voce (i_1, ..., i_n) -th ha il valore f(X_1[i_1], ..., X_n[i_n]) per tutti i set di indici validi (i_1, ..., i_n). Chiaramente, per ogni i in {1, ..., n}, tutti gli elementi di X_i in multi.outer(f, X_1,...,X_i,..., X_n) devono essere argomenti i-es ammissibili per la funzione f. Per il caso n = 2, multi.outer farebbe la stessa cosa di outer, anche se avrebbe una firma diversa (IOW, multi.outer(f, X, Y) equivale a outer(X, Y, f)).

È importante notare che, sebbene gli argomenti X_1, ..., X_n di multi.outer siano tutti vettori, non necessariamente hanno tutti la stessa modalità. Per esempio. X_1 e X_2 potrebbero essere c(1, 2, 3) e LETTERS[10:20], rispettivamente.

Grazie!

risposta

16

Questo è un modo: in primo luogo utilizzare Vectorize e outer per definire una funzione che crea una matrice n-dimensionale in cui ogni voce è una lista di argomenti su cui la funzione data sarà da applicare:

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) 
} 

Ora multi.outer ha solo bisogno di invocare apply e do.call su questo "args-matrix":

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

Proviamo questo con una funzione di esempio:

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

Bello! Vedi una domanda simile (ma non altrettanto complessa) con una risposta simile qui: http: // stackoverflow.com/domande/5233308/IS-ci-a-r-funzione-che-vale-a-function-a-ogni-pair-of-colonne/5.233.713 5.233.713 # – Aaron

1

ne dite di questo:


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

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

} 
+0

Credo che l'OP voleva che il risultato fosse in una matrice n-dimensionale, con ogni dimensione corrispondente a ciascun argomento di 'f'. –

+0

+1 per rendermi consapevole di 'expand.grid', ma quando ho provato questo' multi.outer' (per la prima volta) con la funzione test 'function (s, b, l) {substr (s, b, b + l - 1)} ', e' c ("ABCDEFGH", "IJKLMNOP", "QRSTUVWX"), 1: 5, 2: 3' come il resto degli argomenti, ho ottenuto 'Errore nella funzione (s, b, l): argomento (i) inutilizzato (Var1 = "ABCDEFGH", Var2 = "1", Var3 = "2") '. Non ho avuto la possibilità di capire cosa fa la tua implementazione, o perché questo errore. – kjo

0

penso che possiamo farlo usando Vectorize esterno e.

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) 

Ora, sigm1 (x = 1: 3) dà la potenza richiesta

[[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 

L'unico limite con questo frammento di codice è sto utilizzando i valori di default di un = -1: 1 e b = -1: 1. Quando provo a passare lo stesso durante la funzione di chiamata, va in tilt. Per esempio.

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

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

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

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

Non riesco a capire perché il passaggio degli argomenti stia facendo questa differenza nell'output.