为什么外部工作不像我认为的那样(在R中)?

42-*_*42- 23 functional-programming r vectorization

@ hadley 在今天的答案中引用关于功能文章提示,我决定重新审视一个关于outer函数如何工作(或不工作)的持久性谜题.为什么会失败:

outer(0:5, 0:6, sum) # while outer(0:5, 0:6, "+") succeeds
Run Code Online (Sandbox Code Playgroud)

这显示了我认为outer 应该如何处理如下函数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
Run Code Online (Sandbox Code Playgroud)

好的,我没有为该示例准确对齐我的索引,但它不会那么难修复.问题是为什么像sum这样的函数应该能够接受两个参数并返回一个适合于矩阵元素的(原子)值,在传递给base::outer函数时不能这样做?

所以@agstudy为更紧凑的版本提供了灵感,Outer而且他更紧凑:

 Outer <- function(x,y,fun) {
       mat <- matrix(mapply(fun, rep(x, length(y)), 
                                 rep(y, each=length(x))),
                     length(x), length(y))
Run Code Online (Sandbox Code Playgroud)

但问题仍然存在.术语"矢量化"在这里有些含糊不清,我认为"二元"更正确,因为sin并且cos通常意义上的"矢量化".是否存在一个基本的逻辑障碍,期望outer以可以使用非二元函数的方式扩展其论证.

而这里的另一个outer错误可能与我对这个问题缺乏了解有关:

> 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]
Run Code Online (Sandbox Code Playgroud)

ags*_*udy 31

outer(0:5, 0:6, sum) 不工作,因为sum不是"矢量化"(在返回与两个参数相同长度的矢量的意义上).这个例子应该解释不同之处:

 sum(1:2,2:3)
  8
 1:2 + 2:3
 [1] 3 5
Run Code Online (Sandbox Code Playgroud)

你可以sum使用mapply例如矢量化:

identical(outer(0:5, 0:6, function(x,y)mapply(sum,x,y)),
          outer(0:5, 0:6,'+'))
TRUE
Run Code Online (Sandbox Code Playgroud)

PS:一般在使用之前outer我用来browser在调试模式下创建我的函数:

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
Run Code Online (Sandbox Code Playgroud)