“dims [product xx]与对象[xx]的长度不匹配”使用R函数`outer`时出错

问题描述 投票:1回答:2
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):dims [product 36]与object [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
r
2个回答
3
投票

outer(x, y, FUN)x都是以下的向量时,我经常解释y

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必须能够处理xxyy元素。否则,用一个名为FUN的糖函数包裹Vectorize。稍后将给出更多细节。

请注意,“list”也是向量的有效模式。所以outer可以用于一些非标准的东西,如How to perform pairwise operation like `%in%` and set operations for a list of vectors


您也可以将矩阵/数组传递给outer。鉴于它们只是具有“暗淡”属性的向量(可选地带有“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表现得像这样,但许多其他人没有,比如classsumprod。 R中的*apply族函数可以帮助您矢量化函数动作,或者您可以编写自己的循环来实现相同的效果。


另一个值得阅读的优质问答:Why doesn't outer work the way I think it should (in R)?


1
投票

我认为这是因为外部的结果矩阵期望与输入的尺寸相同,但是,类(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"

reprex package创建于2018-09-13(v0.2.0)。

© www.soinside.com 2019 - 2024. All rights reserved.