2011-05-31 6 views
8

L'expression R standard outer(X, Y, f) évalue une matrice dont l'entrée (i, j) -th a la valeur f(X[i], Y[j]).Comment généraliser des dimensions extérieures à n dimensions?

Je souhaite mettre en oeuvre la fonction multi.outer, une généralisation à n dimensions de outer: multi.outer(f, X_1, ..., X_n), où f est une fonction n-aire, produirait un (* ... * longueur longueur (X_1) (X_n)) tableau dont l'entrée (i_1, ..., i_n) -th a la valeur f(X_1[i_1], ..., X_n[i_n]) pour tous les ensembles d'index valides (i_1, ..., i_n). Clairement, pour chaque i dans {1, ..., n}, tous les éléments de X_i dans multi.outer(f, X_1,...,X_i,..., X_n) doivent être permis par des arguments pour la fonction f. Pour le cas n = 2, multi.outer ferait la même chose que outer, bien qu'il aurait une signature différente (IOW, multi.outer(f, X, Y) serait équivalent à outer(X, Y, f)).

Il est important de noter que, bien que les arguments X_1, ..., X_n de multi.outer soient tous des vecteurs, ils n'ont pas nécessairement tous le même mode. Par exemple. X_1 et X_2 pourraient être c(1, 2, 3) et LETTERS[10:20], respectivement.

Merci!

Répondre

16

C'est une façon: utiliser d'abord Vectorize et outer pour définir une fonction qui crée une matrice de dimension n où chaque entrée est une liste d'arguments sur lesquels la fonction donnée sera appliquer:

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

maintenant multi.outer a juste besoin d'invoquer apply et do.call sur cette "args-matrice":

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

Essayons avec un exemple fonction:

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! Voir une question similaire (mais pas aussi complexe) avec une réponse similaire ici: http: // stackoverflow.com/questions/5233308/is-there-a-r-function-that-applique-a-function-to-each-pair-of-columns/5233713 # 5233713 – Aaron

1

Que diriez-vous ceci:


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

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

} 
+0

Je crois que l'OP voulait que le résultat soit dans une matrice à n dimensions, chaque dimension correspondant à chaque argument de 'f'. –

+0

+1 pour m'avoir rendu compte de 'expand.grid', mais quand j'ai essayé ce' multi.outer' (pour la première fois) avec la fonction de test 'function (s, b, l) {substr (s, b, b + l - 1)} ', et' c ("ABCDEFGH", "IJKLMNOP", "QRSTUVWX"), 1: 5, 2: 3' comme le reste des arguments, j'ai 'Erreur dans la fonction (s, b, l): argument (s) non utilisé (s) (Var1 = "ABCDEFGH", Var2 = "1", Var3 = "2") '. Je n'ai pas eu l'occasion de comprendre ce que votre implémentation fait, ni pourquoi cette erreur. – kjo

0

Je pense que nous pouvons le faire en utilisant extra-atmosphérique et vectorisation.

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) 

Maintenant, sigm1 (x = 1: 3) donne la puissance requise

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

Le seul inconvénient avec cet extrait de code est que je suis en utilisant les valeurs par défaut d'un = -1: 1 et b = -1: 1. Quand j'essaie de faire la même chose pendant un appel de fonction, ça ne va pas. Par exemple. Je ne parviens pas à comprendre pourquoi le passage des arguments fait cette différence en sortie.

Questions connexes