【问题标题】:"dims [product xx] do not match the length of object [xx]" error in using R function `outer`“dims [product xx] 与对象 [xx] 的长度不匹配”使用 R 函数`outer` 时出错
【发布时间】:2018-09-13 15:34:02
【问题描述】:
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)

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

【问题讨论】:

  • 有趣的是,funNoError2 &lt;- function(a,b){paste(class(a),b,sep="**")} 也有效...

标签: r


【解决方案1】:

xy 都是具有以下内容的向量时,我经常解释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 必须能够处理 xxyy 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 的行为是这样的,但许多其他函数却不是这样,比如classsumprod。 R 中的*apply 系列函数可以帮助您将函数动作矢量化,或者您可以编写自己的循环来实现相同的效果。


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

【讨论】:

    【解决方案2】:

    我认为这是因为来自外部的结果矩阵期望与您的输入具有相同的维度,但是,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"
    

    reprex package (v0.2.0) 于 2018 年 9 月 13 日创建。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-29
      • 1970-01-01
      • 2020-06-24
      • 1970-01-01
      • 2014-07-16
      • 2018-06-28
      相关资源
      最近更新 更多