如何将外层推广到n维?

发布于 2024-11-13 05:59:23 字数 783 浏览 3 评论 0原文

标准 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_1,...,X_i,..., X_n) 必须是函数 f 允许的第 i 个参数。对于 n=2 的情况,multi.outer 会执行与 outer 相同的操作,尽管它会有不同的签名 (IOW, multi.outer(f , X, Y) 等价于 outer(X, Y, f))。

需要注意的是,虽然 multi.outer 的参数 X_1, ..., X_n 都是向量,但它们不一定都具有相同的模式。例如,X_1 和 X_2 可以分别是 c(1, 2, 3)LETTERS[10:20]

谢谢!

The standard R expression outer(X, Y, f) evaluates to a matrix whose (i, j)-th entry has the value f(X[i], Y[j]).

I would like to implement the function multi.outer, an n-dimensional generalization of outer: multi.outer(f, X_1, ..., X_n), where f is some n-ary function, would produce a (length(X_1) * ... * length(X_n)) array whose (i_1,...,i_n)-th entry has the value f(X_1[i_1], ..., X_n[i_n]) for all valid index sets (i_1,...,i_n). Clearly, for each i in {1, ..., n}, all the elements of X_i in multi.outer(f, X_1,...,X_i,..., X_n) must be allowable i-th arguments for the function f. For the case n=2, multi.outer would do the same thing as outer, although it would have a different signature (IOW, multi.outer(f, X, Y) would be equivalent to outer(X, Y, f)).

It is important to note that, although the arguments X_1, ..., X_n of multi.outer are all vectors, they don't necessarily all have the same mode. E.g. X_1 and X_2 could be c(1, 2, 3) and LETTERS[10:20], respectively.

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

冰雪梦之恋 2024-11-20 05:59:23

这是一种方法:首先使用 Vectorizeouter 定义一个函数,该函数创建一个 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”上调用 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"

This is one way: First use Vectorize and outer to define a function that creates an n-dimensional matrix where each entry is a list of arguments on which the given function will be applied:

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

Now multi.outer just needs to invoke apply and do.call on this "args-matrix" :

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

Let's try this with an example function:

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"
魄砕の薆 2024-11-20 05:59:23

这个怎么样:


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

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

}

How about this:


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

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

}
把梦留给海 2024-11-20 05:59:23

我认为我们可以使用 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,b,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]]
       [,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

此代码片段的唯一缺点是我使用 a=-1:1 和 b=-1:1 的默认值。当我尝试在函数调用期间传递相同的内容时,它会变得混乱。例如,

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

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

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

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

我无法弄清楚为什么传递参数会导致输出出现这种差异。

I think we can do this using Outer and 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,b,sigm,x)
 },SIMPLIFY = FALSE)

Now, sigm1(x=1:3) gives the required output

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

The only draw back with this code snippet is I am using the default values of a=-1:1 and b=-1:1. When I try to pass the same during function calling, it goes haywire. E.g.

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

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

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

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

I am unable to figure out why passing the arguments is making this difference in output.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文