如何将外部尺寸推广到n个尺寸?

问题描述

| 标准R表达式
outer(X,Y,f)
计算得出一个矩阵,其第(i,j)个条目的值为
f(X[i],Y[j])
。 我想实现函数
multi.outer
,即
outer
的n维概括:
multi.outer(f,X_1,...,X_n)
,其中f是一些n元函数,将产生一个(length(X_1)* ... * length(X_n))数组,其中(i_1 ,...,i_n)条目的所有有效索引集(i_1,...,i_n)的值为
f(X_1[i_1],X_n[i_n])
。显然,对于{1,...,n}中的每个i,
multi.outer(f,X_i,X_n)
X_i
的所有元素必须是函数
f
的第i个自变量。对于n = 2的情况,
multi.outer
outer
做相同的事情,尽管它具有不同的签名(IOW,
multi.outer(f,X,Y)
等效于
outer(X,f)
)。 重要的是要注意,尽管
multi.outer
的参数X_1,...,X_n都是向量,但它们不一定都具有相同的模式。例如。 X_1和X_2分别为
c(1,2,3)
LETTERS[10:20]
。 谢谢!     

解决方法

        这是一种方法:首先使用
Vectorize
outer
定义一个函数,该函数创建一个n维矩阵,其中每个条目都是将应用给定函数的参数列表:
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
只需在此“ args-matrix \”上调用
apply
do.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,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

     [,] \"A 3 g\" \"A 4 g\" \"A 5 g\"
[2,] \"B 3 g\" \"B 4 g\" \"B 5 g\"
    ,        这个怎么样:
multi.outer<-function(f,...){

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

}
    ,        我认为我们可以使用Outer和Vectorize做到这一点。
 sigm = function(a=0,b=0,x){
 return(exp(x*a+b))
 }

 sigm1 = Vectorize(function(a=-1:1,b=-1:1,x){

 outer(a,sigm,x)
 },SIMPLIFY = FALSE)
现在,sigm1(x = 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]]
       [,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]        [,] 0.01831564  0.04978707  0.1353353
[2,] 0.36787944  1.00000000  2.7182818
[3,] 7.38905610 20.08553692 54.5981500
使用此代码段的唯一缺点是我正在使用默认值a = -1:1和b = -1:1。当我尝试在函数调用过程中传递相同的内容时,它就很麻烦了。例如。
sigm1(-1:1,-1:1,1:3)

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

[[2]]
 [,]    1

[[3]]
     [,] 54.59815
我无法弄清楚为什么传递参数会在输出中产生这种差异。