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
第一季度:为什么outer(x, y, "funError")
不起作用?
dim(robj)<-c(dX,dY)中的错误: 昏暗[产品36]与对象[1]的长度不匹配
第二季度: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
答案 0 :(得分: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
必须能够处理xx
和yy
element-wise 。否则,用名为FUN
的糖函数包装Vectorize
。稍后会提供更多详细信息。
请注意,“列表”也是向量的有效模式。因此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
,{{1 }}。 R中的prod
系列函数可以帮助您向量化函数操作,也可以编写自己的循环来达到相同的效果。
另一个值得阅读的优质问答:Why doesn't outer work the way I think it should (in R)?
答案 1 :(得分:1)
我认为这是因为从外部得到的矩阵期望与您的输入具有相同的尺寸,但是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-09-13创建。