2013-08-07 3 views
20

Richiesto da @ hadley's article on functionals referenced in an answer today, ho deciso di rivisitare un enigma persistente su come funziona la funzione outer (o meno). Perché questo venga menoPerché il lavoro esterno non funziona come penso io (in R)?

outer(0:5, 0:6, sum) # while outer(0:5, 0:6, "+") succeeds 

Questo dimostra come penso outerdovrebbe gestire una funzione come sum:

Outer <- function(x,y,fun) { 
    mat <- matrix(NA, length(x), length(y)) 
    for (i in seq_along(x)) { 
      for (j in seq_along(y)) {mat[i,j] <- fun(x[i],y[j])} } 
    mat} 

> Outer(0:5, 0:6, `+`) 
    [,1] [,2] [,3] [,4] [,5] [,6] [,7] 
[1,] 0 1 2 3 4 5 6 
[2,] 1 2 3 4 5 6 7 
[3,] 2 3 4 5 6 7 8 
[4,] 3 4 5 6 7 8 9 
[5,] 4 5 6 7 8 9 10 
[6,] 5 6 7 8 9 10 11 

OK, io non ho il mio indici esattamente allineati per questo esempio, ma non sarebbe così difficile da risolvere. La domanda è: perché una funzione come sum che dovrebbe essere in grado di accettare due argomenti e restituire un valore (atomico) adatto per un elemento matrix, non può farlo quando viene passata alla funzione base::outer?

Così @agstudy ha dato ispirazione per una versione più compatta del Outer e la sua è ancora più compatta:

Outer <- function(x,y,fun) { 
     mat <- matrix(mapply(fun, rep(x, length(y)), 
           rep(y, each=length(x))), 
        length(x), length(y)) 

Tuttavia, la questione rimane. Il termine "vettorializzato" è alquanto ambiguo e penso che "diadico" sia più corretto, dal momento che sin e cos sono "vettorizzati" nel senso comune del termine. Esiste una fondamentale barriera logica per prevedere che outer espanda i suoi argomenti in modo da poter utilizzare le funzioni non diadiche.

Ed ecco un altro outer -Errore che è probabilmente simile collegato alla mia mancanza di comprensione di questo problema:

> Vectorize(sum) 
function (..., na.rm = FALSE) .Primitive("sum") 
> outer(0:5, 0:6, function(x,y) Vectorize(sum)(x,y)) 
Error in outer(0:5, 0:6, function(x, y) Vectorize(sum)(x, y)) : 
    dims [product 42] do not match the length of object [1] 
+0

le tue funzioni sono ok, ma sto indovinando molto più lentamente, quindi non eccezionale per un'implementazione R di 'outer'; è stato implementato in C++ invece che la versione 'sum' avrebbe probabilmente funzionato – eddi

+3

stai cercando questo nel tuo ultimo esempio:' outer (0: 5, 0: 6, Vectorize (funzione (x, y) sum (x, y))) ' – eddi

+0

@eddi: Avrei svalutato che se offerto come risposta. –

risposta

29

outer(0:5, 0:6, sum) non funzionano perché sum non è "vettorializzare" (nel senso di un ritorno vettore della stessa lunghezza dei suoi due argomenti). Questo esempio dovrebbe spiegare la differenza:

sum(1:2,2:3) 
    8 
1:2 + 2:3 
[1] 3 5 

È possibile vectorize sum usando mapply ad esempio:

identical(outer(0:5, 0:6, function(x,y)mapply(sum,x,y)), 
      outer(0:5, 0:6,'+')) 
TRUE 

PS: In genere prima di utilizzare outer Io uso browser per creare la mia funzione nella modalità di debug:

outer(0:2, 1:3, function(x,y)browser()) 
Called from: FUN(X, Y, ...) 
Browse[1]> x 
[1] 0 1 2 0 1 2 0 1 2 
Browse[1]> y 
[1] 1 1 1 2 2 2 3 3 3 
Browse[1]> sum(x,y) 
[1] 27   ## this give an error 
Browse[1]> x+y 
[1] 1 2 3 2 3 4 3 4 5 ## this is vectorized 
+0

Un sottigliezza da '? Sum':' ... numerico o vettori complessi o logici'. Quindi 'sum (c (1,2,3)) = sum (1,2,3) = sum (c (1,2), 3)' –

+0

Mi piace l'esempio del browser. Lo proverò con il mio seguito Q. di Vectorize (somma). Ma non credo che solo dire "è vettorializzato" sia abbastanza specifico.) –

+1

@DWin Sono d'accordo per la terminologia qui. "Vectorized" non è il termine buono qui. 'Diadico' forse? sentiti libero di modificare la mia risposta. – agstudy