2011-05-31 7 views
8

Стандартное выражение R outer(X, Y, f) оценивает матрицу, чья (i, j) -я запись имеет значение f(X[i], Y[j]).Как обобщить внешние размеры?

Я хотел бы реализовать функцию multi.outer, п-мерное обобщение outer: multi.outer(f, X_1, ..., X_n), где е некоторая п-арной функции, будет производить (длина (x_1) * ... * длина (X_n)) массив, чья (i_1, ..., i_n) -я запись имеет значение f(X_1[i_1], ..., X_n[i_n]) для всех допустимых наборов индексов (i_1, ..., i_n). Ясно, что для каждого i из {1, ..., n} все элементы X_i в multi.outer(f, X_1,...,X_i,..., X_n) должны быть допустимыми i-м аргументом для функции f. Для случая n = 2 multi.outer будет делать то же самое, что и outer, хотя у него будет другая подпись (IOW, multi.outer(f, X, Y) будет эквивалентно outer(X, Y, f)).

Важно отметить, что хотя аргументы X_1, ..., X_n из multi.outer - все векторы, они не обязательно имеют одинаковый режим. Например. X_1 и X_2 могут быть c(1, 2, 3) и LETTERS[10:20], соответственно.

Спасибо!

ответ

16

Это один из способов: Сначала Vectorize и outer определить функцию, которая создает п-мерный матрицу, где каждая запись представляет собой список аргументов, на которых данная функция будет применяться:

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

Теперь multi.outer просто нужно вызвать applydo.call и на этом "арг-матрица":

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

Давайте попробуем это с примером функции:

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

Ницца! См. Аналогичный (но не такой сложный) вопрос с похожим ответом здесь: http: // stackoverflow.ком/вопросы/5233308/IS-есть-а-р-функцию-что-относится-а-функция-на-каждый-пара-из-столбцов/5233713 # 5233713 – Aaron

1

Как об этом:


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

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

} 
+0

Я считаю, что OP хотел, чтобы результат был в n-мерной матрице с каждым размером, соответствующим каждому аргументу 'f'. –

+0

+1 для того, чтобы сообщить мне об 'expand.grid', но когда я попробовал этот' multi.outer' (впервые) с функцией функции test (s, b, l) {substr (s, b, b + l - 1)} 'и' c («ABCDEFGH», «IJKLMNOP», «QRSTUVWX»), 1: 5, 2: 3', как остальные аргументы, я получил «Ошибка в функции (s, b, l): неиспользуемый аргумент (ы) (Var1 = "ABCDEFGH", Var2 = "1", Var3 = "2") '. У меня не было возможности выяснить, что делает ваша реализация, или почему эта ошибка. – kjo

0

Я думаю, что мы можем сделать это с помощью Outer и векторизации.

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) 

Теперь sigm1 (х = 1: 3) дает требуемой мощность

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

только отдернуть с этим фрагментом кода я использую значение по умолчанию а = -1: 1 и b = -1: 1. Когда я пытаюсь передать то же самое во время вызова функции, он идет haywire. Например.

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

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

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

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

Я не могу понять, почему передача аргументов делает эту разницу в выходе.