2013-08-07 8 views
20

Podpowiedziane przez @ hadley's article on functionals referenced in an answer today, postanowiłem wrócić do uporczywej łamigłówki o tym, jak działa funkcja outer (lub nie). Dlaczego tego nie robi:Dlaczego praca zewnętrzna nie wygląda tak, jak powinien (w R)?

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

To pokazuje, jak myślę outerpowinny obsługiwać funkcji takich jak 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, ja nie mam indeksy dokładnie dopasowane do tego przykładu, ale nie byłoby to trudne do naprawienia. Pytanie brzmi, dlaczego funkcja taka jak sum, która powinna być w stanie przyjąć dwa argumenty i zwrócić (atomową) wartość odpowiednią dla elementu macierzy, nie może tego zrobić po przejściu do funkcji base::outer?

Więc @agstudy dał natchnienie dla bardziej kompaktowej wersji Outer i jego jest jeszcze bardziej kompaktowy:

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

Jednak pytanie pozostaje. Termin "wektoryzacja" jest tu nieco niejednoznaczny i myślę, że "diadyczna" jest bardziej poprawna, ponieważ sin i cos są "wektoryzowane" w zwykłym tego słowa znaczeniu. Czy istnieje podstawowa logiczna bariera, aby oczekiwać, że outer rozszerzy swoje argumenty w taki sposób, aby można było użyć funkcji nieadadycznych.

A oto kolejny outer -error że prawdopodobnie podobnie podłączony do mojego braku zrozumienia tego problemu:

> 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

Twoje funkcje są w porządku, ale zgaduję, że jest znacznie wolniej, więc nie jest to zbyt dobre dla implementacji R 'zewnętrznego'; był zewnętrzny zaimplementowany w C++ zamiast tego, wersja 'sum' prawdopodobnie pracowała – eddi

+3

, której szukasz w swoim ostatnim przykładzie:' zewnętrzny (0: 5, 0: 6, Vectorize (suma funkcji (x, y) (x, y))) ' – eddi

+0

@eddi: Chciałbym przegłosować, że jeśli oferowane jako odpowiedź. –

Odpowiedz

29

outer(0:5, 0:6, sum) nie działa, ponieważ nie jest sum „wektorowy” (w sensie Zwracanie wektor o tej samej długości, co jego dwa argumenty). Ten przykład powinien wyjaśnić różnicę:

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

Można Wektoryzacji sum użyciu mapply na przykład:

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

PS: Generalnie przed użyciem outer używam browser stworzyć moją funkcję w trybie debugowania:

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

Subtelność z '? Sum':' ... wektorów numerycznych lub złożonych lub logicznych'. Tak więc 'suma (c (1,2,3)) = suma (1,2,3) = suma (c (1,2), 3)' –

+0

Podoba mi się przykład przeglądarki. Spróbuję tego z moim dodatkiem do Vectorize (suma) Q. (Ale nie sądzę, że samo powiedzenie "wektoryzacja" jest wystarczająco specyficzne.) –

+1

@DWin Zgadzam się na terminologię tutaj. "Wektoryzacja" nie jest tutaj dobrym terminem. może "diadyczna"? zapraszam do edycji mojej odpowiedzi. – agstudy