当x 和y 都是具有以下内容的向量时,我经常解释outer(x, y, FUN):
xx <- rep(x, times = length(y))
yy <- rep(y, each = length(x))
zz <- FUN(xx, yy)
stopifnot(length(zz) == length(x) * length(y)) ## length = product?
z <- matrix(zz, length(x), length(y))
funError 失败是因为 zz 的长度为 1,而 funNoError 不会因为在粘贴 a(长度 > 1 的向量)和 class(a)(长度-1 向量)。
这是说明性的,您将看到为什么 outer(1:5, 1:5, "+") 有效但 outer(1:5, 1:5, sum) 失败。基本上,FUN 必须能够处理 xx 和 yy element-wise。否则,使用名为Vectorize 的糖函数包装FUN。更多细节稍后给出。
请注意,“列表”也是向量的有效模式。所以outer 可以用于一些非标准的东西,比如How to perform pairwise operation like `%in%` and set operations for a list of vectors。
您也可以将矩阵/数组传递给outer。鉴于它们只是具有“dim”属性(可选地带有“dimnames”)的向量,outer 的工作方式不会改变。
x <- matrix(1:4, 2, 2) ## has "dim"
y <- matrix(1:9, 3, 3) ## has "dim"
xx <- rep(x, times = length(y)) ## xx <- rep(c(x), times = length(y))
yy <- rep(y, each = length(x)) ## yy <- rep(c(y), each = length(x))
zz <- "*"(xx, yy)
stopifnot(length(zz) == length(x) * length(y)) ## length = product?
z <- "dim<-"( zz, c(dim(x), dim(y)) )
z0 <- outer(x, y, "*")
all.equal(z, z0)
#[1] TRUE
?outer 用通俗易懂的语言解释了上面的代码。
‘X’ and ‘Y’ must be suitable arguments for ‘FUN’. Each will be
extended by ‘rep’ to length the products of the lengths of ‘X’ and
‘Y’ before ‘FUN’ is called.
‘FUN’ is called with these two extended vectors as arguments (plus
any arguments in ‘...’). It must be a vectorized function (or the
name of one) expecting at least two arguments and returning a
value with the same length as the first (and the second).
Where they exist, the [dim]names of ‘X’ and ‘Y’ will be copied to
the answer, and a dimension assigned which is the concatenation of
the dimensions of ‘X’ and ‘Y’ (or lengths if dimensions do not
exist).
“矢量化”这个词不是 the most discussed one in R on performance。它的意思是“向量化函数的动作”:
## for FUN with a single argument
FUN( c(x1, x2, x3, x4) ) = c( FUN(x1), FUN(x2), FUN(x3), FUN(x4) )
## for FUN with two arguments
FUN( c(x1, x2, x3, x4), c(y1, y2, y3, y4) )
= c( FUN(x1, y1), FUN(x2, y2), FUN(x3, y3), FUN(x4, y4) )
有些函数说"+"、"*"、paste 的行为是这样的,但许多其他函数却不是这样,比如class、sum、prod。 R 中的*apply 系列函数可以帮助您将函数动作矢量化,或者您可以编写自己的循环来实现相同的效果。
另一个值得一读的优质问答:Why doesn't outer work the way I think it should (in R)?