使用 R 函数"outer"时出错"dims [product xx] do not match the length of object [xx]"


x <- 1:9
names(x) <- paste0("x",x)
y <- 2:5
names(y) <- paste0("y",y)
fun1      <-function(a, b) {paste(class(a),b, sep = "**")} #works
funError  <-function(a, b) {paste(class(a),class(b), sep = "**")} #does not work with outer
funNoError<-function(a, b) {paste(a,class(a),class(b),b, sep = "**")}  #works with outer  
funError(1,2) #is a valid function
outer(x, y, "funError") # fails
outer(x, y, "funNoError") # works

Q1:为什么outer(x, y, "funError")不起作用?

dim(robj( <- c(dX, dY( 中的错误: 暗淡 [产品 36] 与对象 [1] 的长度不匹配

Q2: 为什么outer(x, y, "funNoError")有效?它非常相似。

  • 我能看到的唯一区别是funError的每个"结果"都是相同的("numeric**numeric"(。

  • 如果始终具有相同的值是问题:为什么这里有效?

outer(rep(0,7), 1:10, "^")


好的,我明白了:

lol  <- function(a,b) {"lol"}
lol_v<- Vectorize(lol)
outer(x, y, "lol")   # fails with same Error
outer(x, y, "lol_v") # works as expected

我经常解释outer(x, y, FUN)xy都是具有以下内容的向量时:

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。否则,用称为Vectorize的糖函数包装FUN。更多细节将在后面给出。

请注意,"列表"也是向量的有效模式。因此,outer可以用于一些非标准的事情,例如如何执行成对操作(如"%in%"(和向量列表的设置操作。


您也可以将矩阵/数组传递给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).

"矢量化"这个词并不是R中关于性能的讨论最多的一个。它的意思是"矢量化函数的操作":

## 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这样的行为,但许多其他函数则不然,比如classsumprod。R 中的*apply系列函数可以帮助您矢量化函数动作,或者您可以编写自己的循环来实现相同的效果。


另一个值得一读的高质量问答:为什么外部没有按照我认为的方式工作(在R中(?

我认为这是因为来自外部的结果矩阵期望与您的输入具有相同的维度,但是,class(a( 的长度仅为 1,因此矩阵维度不匹配。尝试

funError2 <- function(a,b){paste(rep(class(a), length(a)),rep(class(b), length(b)), sep = "**")}
outer(x,y, "funError2")
#>    y2                 y3                 y4                
#> x1 "integer**integer" "integer**integer" "integer**integer"
#> x2 "integer**integer" "integer**integer" "integer**integer"
#> x3 "integer**integer" "integer**integer" "integer**integer"
#> x4 "integer**integer" "integer**integer" "integer**integer"
#> x5 "integer**integer" "integer**integer" "integer**integer"
#> x6 "integer**integer" "integer**integer" "integer**integer"
#> x7 "integer**integer" "integer**integer" "integer**integer"
#> x8 "integer**integer" "integer**integer" "integer**integer"
#> x9 "integer**integer" "integer**integer" "integer**integer"
#>    y5                
#> x1 "integer**integer"
#> x2 "integer**integer"
#> x3 "integer**integer"
#> x4 "integer**integer"
#> x5 "integer**integer"
#> x6 "integer**integer"
#> x7 "integer**integer"
#> x8 "integer**integer"
#> x9 "integer**integer"

创建于 2018-09-13 由 reprex 软件包 (v0.2.0(。

最新更新